From 686f27a404ef42fb63a6bb72991f69a2e2f23ced Mon Sep 17 00:00:00 2001 From: jan-vcapgemini Date: Wed, 17 Apr 2024 16:57:05 +0200 Subject: [PATCH 01/20] #12: added Android Studio IDE added Android Studio IdeToolCommandlet with first runIde implementation for Windows and Mac added symlink creation --- .../ide/commandlet/CommandletManagerImpl.java | 2 + .../ide/tool/androidstudio/AndroidStudio.java | 121 ++++++++++++++++++ cli/src/main/resources/nls/Ide.properties | 1 + cli/src/main/resources/nls/Ide_de.properties | 1 + 4 files changed, 125 insertions(+) create mode 100644 cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java 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 ef80dbaea..c648daecd 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 @@ -3,6 +3,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.androidstudio.AndroidStudio; import com.devonfw.tools.ide.tool.aws.Aws; import com.devonfw.tools.ide.tool.az.Azure; import com.devonfw.tools.ide.tool.cobigen.Cobigen; @@ -95,6 +96,7 @@ public CommandletManagerImpl(IdeContext context) { add(new Jasypt(context)); add(new Docker(context)); add(new Sonar(context)); + add(new AndroidStudio(context)); } private void add(Commandlet commandlet) { diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java b/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java new file mode 100644 index 000000000..5c3e06e6c --- /dev/null +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java @@ -0,0 +1,121 @@ +package com.devonfw.tools.ide.tool.androidstudio; + +import com.devonfw.tools.ide.cli.CliArgument; +import com.devonfw.tools.ide.common.Tag; +import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.io.FileAccess; +import com.devonfw.tools.ide.process.ProcessContext; +import com.devonfw.tools.ide.process.ProcessErrorHandling; +import com.devonfw.tools.ide.process.ProcessMode; +import com.devonfw.tools.ide.process.ProcessResult; +import com.devonfw.tools.ide.step.Step; +import com.devonfw.tools.ide.tool.ide.IdeToolCommandlet; +import com.devonfw.tools.ide.tool.ide.PluginDescriptor; +import com.devonfw.tools.ide.tool.java.Java; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Set; + +/** + * {@link IdeToolCommandlet} for AndroidStudio. + */ +public class AndroidStudio extends IdeToolCommandlet { + + private static final String STUDIO = "studio"; + + private static final String STUDIO64_EXE = STUDIO + "64.exe"; + + private static final String STUDIO_SCRIPT = STUDIO + ".sh"; + + /** + * The constructor. + * + * @param context the {@link IdeContext}. + */ + public AndroidStudio(IdeContext context) { + + super(context, "android-studio", Set.of(Tag.ANDROID_STUDIO)); + } + + @Override + protected void runIde(String... args) { + + install(true); + + Step stepRun = this.context.newStep("Running Android Studio"); + try { + ProcessResult result; + if (this.context.getSystemInfo().isMac()) { + result = runAndroidStudio(ProcessMode.BACKGROUND, CliArgument.prepend(args, "open", "-na", this.context.getWorkspacePath().toString())); + } else { + result = runAndroidStudio(ProcessMode.BACKGROUND, CliArgument.prepend(args, this.context.getWorkspacePath().toString())); + } + if (result.isSuccessful()) { + stepRun.success("Running Android Studio successfully."); + } else { + stepRun.isFailure(); + } + + } catch (Exception e) { + stepRun.error(e, "Failed to do something."); + } finally { + stepRun.end(); + } + + } + + /** + * Runs AndroidStudio application. + * + * @param processMode - the {@link ProcessMode}. + * @param args the individual arguments to pass to Android Studio. + * @return the {@link ProcessResult}. + */ + protected ProcessResult runAndroidStudio(ProcessMode processMode, String... args) { + + Path toolPath; + // TODO: Check if this can be optimized. + if (this.context.getSystemInfo().isMac()) { + toolPath = getToolBinPath().resolve(STUDIO); + if (!Files.exists(toolPath)) { + toolPath = getToolPath().resolve(STUDIO); + } + } else { + toolPath = getToolBinPath().resolve(STUDIO64_EXE); + } + ProcessContext pc = this.context.newProcess(); + pc.executable(toolPath); + if (processMode == ProcessMode.DEFAULT_CAPTURE) { + pc.errorHandling(ProcessErrorHandling.ERROR); + } + pc.addArgs(args); + + return pc.run(processMode); + } + + @Override + public boolean install(boolean silent) { + + getCommandlet(Java.class).install(); + return super.install(silent); + } + + @Override + protected void postInstall() { + + super.postInstall(); + Path scriptPath = getToolBinPath().resolve(STUDIO_SCRIPT); + + // TODO: Check if this is still needed. + if (Files.exists(scriptPath)) { + FileAccess fileAccess = this.context.getFileAccess(); + fileAccess.symlink(scriptPath, getToolBinPath().resolve(STUDIO), true); + } + } + + @Override + public void installPlugin(PluginDescriptor plugin) { + + } +} diff --git a/cli/src/main/resources/nls/Ide.properties b/cli/src/main/resources/nls/Ide.properties index ba02eb18b..68c2185d2 100644 --- a/cli/src/main/resources/nls/Ide.properties +++ b/cli/src/main/resources/nls/Ide.properties @@ -2,6 +2,7 @@ usage=Usage: values=Values: commandlets=Available commandlets: options=Options: +cmd-android-studio=Tool commandlet for Android Studio (IDE). cmd-aws=Tool commandlet for AWS CLI. cmd-az=Tool commandlet for Azure CLI. cmd---version=Print the version of IDEasy. diff --git a/cli/src/main/resources/nls/Ide_de.properties b/cli/src/main/resources/nls/Ide_de.properties index a7d523fb1..c2b4e9298 100644 --- a/cli/src/main/resources/nls/Ide_de.properties +++ b/cli/src/main/resources/nls/Ide_de.properties @@ -2,6 +2,7 @@ usage=Verwendung: values=Werte: commandlets=Verfügbare Kommandos: options=Optionen: +cmd-android-studio=Werkzeug Kommando für Android Studio (IDE). cmd-aws=Werkzeug Kommando für AWS Kommandoschnittstelle. cmd-az=Werkzeug Kommando für Azure Kommandoschnittstelle. cmd---version=Gibt die Version von IDEasy aus. From 79b8c8488edc861e8d9fe18a0c3f9d98bb29cb16 Mon Sep 17 00:00:00 2001 From: jan-vcapgemini Date: Thu, 18 Apr 2024 14:17:49 +0200 Subject: [PATCH 02/20] #12: inversed OS checks --- .../ide/tool/androidstudio/AndroidStudio.java | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java b/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java index 5c3e06e6c..17f6e0b4d 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java @@ -26,7 +26,7 @@ public class AndroidStudio extends IdeToolCommandlet { private static final String STUDIO64_EXE = STUDIO + "64.exe"; - private static final String STUDIO_SCRIPT = STUDIO + ".sh"; + private static final String STUDIO_BASH = STUDIO + ".sh"; /** * The constructor. @@ -46,10 +46,10 @@ protected void runIde(String... args) { Step stepRun = this.context.newStep("Running Android Studio"); try { ProcessResult result; - if (this.context.getSystemInfo().isMac()) { - result = runAndroidStudio(ProcessMode.BACKGROUND, CliArgument.prepend(args, "open", "-na", this.context.getWorkspacePath().toString())); - } else { + if (this.context.getSystemInfo().isWindows()) { result = runAndroidStudio(ProcessMode.BACKGROUND, CliArgument.prepend(args, this.context.getWorkspacePath().toString())); + } else { + result = runAndroidStudio(ProcessMode.BACKGROUND, CliArgument.prepend(args, "open", "-na", this.context.getWorkspacePath().toString())); } if (result.isSuccessful()) { stepRun.success("Running Android Studio successfully."); @@ -58,7 +58,7 @@ protected void runIde(String... args) { } } catch (Exception e) { - stepRun.error(e, "Failed to do something."); + stepRun.error(e, "Failed to run Android Studio."); } finally { stepRun.end(); } @@ -76,16 +76,22 @@ protected ProcessResult runAndroidStudio(ProcessMode processMode, String... args Path toolPath; // TODO: Check if this can be optimized. - if (this.context.getSystemInfo().isMac()) { + if (this.context.getSystemInfo().isWindows()) { + toolPath = getToolBinPath().resolve(STUDIO64_EXE); + } else { + // check bin folder toolPath = getToolBinPath().resolve(STUDIO); if (!Files.exists(toolPath)) { + // check tool root folder toolPath = getToolPath().resolve(STUDIO); } - } else { - toolPath = getToolBinPath().resolve(STUDIO64_EXE); } ProcessContext pc = this.context.newProcess(); - pc.executable(toolPath); + + if (Files.exists(toolPath)) { + pc.executable(toolPath); + } + if (processMode == ProcessMode.DEFAULT_CAPTURE) { pc.errorHandling(ProcessErrorHandling.ERROR); } @@ -105,7 +111,7 @@ public boolean install(boolean silent) { protected void postInstall() { super.postInstall(); - Path scriptPath = getToolBinPath().resolve(STUDIO_SCRIPT); + Path scriptPath = getToolBinPath().resolve(STUDIO_BASH); // TODO: Check if this is still needed. if (Files.exists(scriptPath)) { From fe6feae7c083aed5c3ddc5000ffd503fdda5759d Mon Sep 17 00:00:00 2001 From: jan-vcapgemini Date: Mon, 22 Apr 2024 16:03:05 +0200 Subject: [PATCH 03/20] adjusted .gitattributes --- .gitattributes | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index 1ffaa5d71..931eb4a75 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,8 @@ * eol=lf *.bat eol=crlf -*.png -text +*.png binary +*.zip binary +*.tgz binary +*.tar binary +*.bz2 binary +*.gz binary \ No newline at end of file From 136a20dcb185c08574db6cff2ea79cbffb246e83 Mon Sep 17 00:00:00 2001 From: jan-vcapgemini Date: Mon, 22 Apr 2024 16:04:26 +0200 Subject: [PATCH 04/20] fixed line endings --- .../java/com/devonfw/tools/ide/step/Step.java | 488 +++++++-------- .../com/devonfw/tools/ide/step/StepImpl.java | 590 +++++++++--------- .../tools/ide/tool/PackageManagerCommand.java | 52 +- .../tools/ide/variable/IdeVariables.java | 150 ++--- .../devonfw/tools/ide/log/IdeSlf4jLogger.java | 154 ++--- .../com/devonfw/tools/ide/step/StepTest.java | 266 ++++---- documentation/symlink.adoc | 44 +- 7 files changed, 872 insertions(+), 872 deletions(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/step/Step.java b/cli/src/main/java/com/devonfw/tools/ide/step/Step.java index 94e8e85d0..2536733c2 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/step/Step.java +++ b/cli/src/main/java/com/devonfw/tools/ide/step/Step.java @@ -1,245 +1,245 @@ -package com.devonfw.tools.ide.step; - -import java.util.concurrent.Callable; - -/** - * Interface for a {@link Step} of the process. Allows to split larger processes into smaller steps that are traced and - * measured. At the end you can get a report with the hierarchy of all steps and their success/failure status, duration - * in absolute and relative numbers to gain transparency.
The typical use should follow this pattern: - * - *
- * Step step = context.{@link com.devonfw.tools.ide.context.IdeContext#newStep(String) newStep}("My step description");
- * try {
- *   // ... do something ...
- *   step.{@link #success(String) success}("Did something successfully.");
- * } catch (Exception e) {
- *   step.{@link #error(Throwable, String)}(e, "Failed to do something.");
- * } finally {
- *   step.{@link #end() end()};
- * }
- * 
- */ -public interface Step { - - /** Empty object array for no parameters. */ - Object[] NO_PARAMS = new Object[0]; - - /** - * @return the name of this {@link Step} as given to constructor. - */ - String getName(); - - /** - * @return the duration of this {@link Step} from construction to {@link #success()} or {@link #end()}. Will be - * {@code 0} if not {@link #end() ended}. - */ - long getDuration(); - - /** - * @return {@code Boolean#TRUE} if this {@link Step} has {@link #success() succeeded}, {@code Boolean#FALSE} if the - * {@link Step} has {@link #end() ended} without {@link #success() success} and {@code null} if the {@link Step} is - * still running. - */ - Boolean getSuccess(); - - /** - * @return {@code true} if this step completed {@link #success() successfully}, {@code false} otherwise. - */ - default boolean isSuccess() { - - return Boolean.TRUE.equals(getSuccess()); - } - - /** - * @return {@code true} if this step {@link #end() ended} without {@link #success() success} e.g. with an - * {@link #error(String) error}, {@code false} otherwise. - */ - default boolean isFailure() { - - return Boolean.FALSE.equals(getSuccess()); - } - - /** - * @return {@code true} if this step is silent and not logged by default, {@code false} otherwise (default). - */ - boolean isSilent(); - - /** - * Should be called to end this {@link Step} {@link #getSuccess() successfully}. May be called only once. - */ - default void success() { - - success(null); - } - - /** - * Should be called to end this {@link Step} {@link #getSuccess() successfully}. May be called only once. - * - * @param message the explicit message to log as success. - */ - default void success(String message) { - - success(message, (Object[]) null); - } - - /** - * Should be called to end this {@link Step} {@link #getSuccess() successfully}. May be called only once. - * - * @param message the explicit message to log as success. - * @param args the optional arguments to fill as placeholder into the {@code message}. - */ - void success(String message, Object... args); - - /** - * Ensures this {@link Step} is properly ended. Has to be called from a finally block. - */ - void end(); - - /** - * Should be called to end this {@link Step} as {@link #isFailure() failure} with an explicit error message. May be - * called only once. - * - * @param message the explicit message to log as error. - */ - default void error(String message) { - - error(null, message); - } - - /** - * Should be called to end this {@link Step} as {@link #isFailure() failure} with an explicit error message and/or - * {@link Throwable exception}. May be called only once. - * - * @param message the explicit message to log as error. - * @param args the optional arguments to fill as placeholder into the {@code message}. - */ - default void error(String message, Object... args) { - - error(null, message, args); - } - - /** - * Should be called to end this {@link Step} as {@link #isFailure() failure} with an explicit error message and/or - * {@link Throwable exception}. May be called only once. - * - * @param error the catched {@link Throwable}. - */ - default void error(Throwable error) { - - error(error, false); - } - - /** - * Should be called to end this {@link Step} as {@link #isFailure() failure} with an explicit error message and/or - * {@link Throwable exception}. May be called only once. - * - * @param error the catched {@link Throwable}. - * @param suppress to suppress the error logging (if error will be rethrown and duplicated error messages shall be - * avoided). - */ - default void error(Throwable error, boolean suppress) { - - assert (error != null); - error(error, suppress, null, (Object[]) null); - } - - /** - * Should be called to end this {@link Step} as {@link #isFailure() failure} with an explicit error message and/or - * {@link Throwable exception}. May be called only once. - * - * @param error the catched {@link Throwable}. May be {@code null} if only a {@code message} is provided. - * @param message the explicit message to log as error. - */ - default void error(Throwable error, String message) { - - error(error, message, (Object[]) null); - } - - /** - * Should be called to end this {@link Step} as {@link #isFailure() failure} with an explicit error message and/or - * {@link Throwable exception}. May be called only once. - * - * @param error the catched {@link Throwable}. May be {@code null} if only a {@code message} is provided. - * @param message the explicit message to log as error. - * @param args the optional arguments to fill as placeholder into the {@code message}. - */ - default void error(Throwable error, String message, Object... args) { - - error(error, false, message, args); - } - - /** - * Should be called to end this {@link Step} as {@link #isFailure() failure} with an explicit error message and/or - * {@link Throwable exception}. May be called only once. - * - * @param error the catched {@link Throwable}. May be {@code null} if only a {@code message} is provided. - * @param suppress to suppress the error logging (if error will be rethrown and duplicated error messages shall be - * avoided). - * @param message the explicit message to log as error. - * @param args the optional arguments to fill as placeholder into the {@code message}. - */ - void error(Throwable error, boolean suppress, String message, Object... args); - - /** - * @return the parent {@link Step} or {@code null} if there is no parent. - */ - Step getParent(); - - /** - * @param i the index of the requested parameter. Should be in the range from {@code 0} to - * {@link #getParameterCount()}-1. - * @return the parameter at the given index {@code i} or {@code null} if no such parameter exists. - */ - Object getParameter(int i); - - /** - * @return the number of {@link #getParameter(int) parameters}. - */ - int getParameterCount(); - - /** - * @param stepCode the {@link Runnable} to {@link Runnable#run() execute} for this {@link Step}. - */ - default void run(Runnable stepCode) { - - try { - stepCode.run(); - if (getSuccess() == null) { - success(); - } - } catch (RuntimeException | Error e) { - error(e); - throw e; - } finally { - end(); - } - } - - /** - * @param stepCode the {@link Callable} to {@link Callable#call() execute} for this {@link Step}. - * @param type of the return value. - * @return the value returned from {@link Callable#call()}. - */ - default R call(Callable stepCode) { - - try { - R result = stepCode.call(); - if (getSuccess() == null) { - success(); - } - return result; - } catch (Throwable e) { - error(e); - if (e instanceof RuntimeException re) { - throw re; - } else if (e instanceof Error error) { - throw error; - } else { - throw new IllegalStateException(e); - } - } finally { - end(); - } - } - +package com.devonfw.tools.ide.step; + +import java.util.concurrent.Callable; + +/** + * Interface for a {@link Step} of the process. Allows to split larger processes into smaller steps that are traced and + * measured. At the end you can get a report with the hierarchy of all steps and their success/failure status, duration + * in absolute and relative numbers to gain transparency.
The typical use should follow this pattern: + * + *
+ * Step step = context.{@link com.devonfw.tools.ide.context.IdeContext#newStep(String) newStep}("My step description");
+ * try {
+ *   // ... do something ...
+ *   step.{@link #success(String) success}("Did something successfully.");
+ * } catch (Exception e) {
+ *   step.{@link #error(Throwable, String)}(e, "Failed to do something.");
+ * } finally {
+ *   step.{@link #end() end()};
+ * }
+ * 
+ */ +public interface Step { + + /** Empty object array for no parameters. */ + Object[] NO_PARAMS = new Object[0]; + + /** + * @return the name of this {@link Step} as given to constructor. + */ + String getName(); + + /** + * @return the duration of this {@link Step} from construction to {@link #success()} or {@link #end()}. Will be + * {@code 0} if not {@link #end() ended}. + */ + long getDuration(); + + /** + * @return {@code Boolean#TRUE} if this {@link Step} has {@link #success() succeeded}, {@code Boolean#FALSE} if the + * {@link Step} has {@link #end() ended} without {@link #success() success} and {@code null} if the {@link Step} is + * still running. + */ + Boolean getSuccess(); + + /** + * @return {@code true} if this step completed {@link #success() successfully}, {@code false} otherwise. + */ + default boolean isSuccess() { + + return Boolean.TRUE.equals(getSuccess()); + } + + /** + * @return {@code true} if this step {@link #end() ended} without {@link #success() success} e.g. with an + * {@link #error(String) error}, {@code false} otherwise. + */ + default boolean isFailure() { + + return Boolean.FALSE.equals(getSuccess()); + } + + /** + * @return {@code true} if this step is silent and not logged by default, {@code false} otherwise (default). + */ + boolean isSilent(); + + /** + * Should be called to end this {@link Step} {@link #getSuccess() successfully}. May be called only once. + */ + default void success() { + + success(null); + } + + /** + * Should be called to end this {@link Step} {@link #getSuccess() successfully}. May be called only once. + * + * @param message the explicit message to log as success. + */ + default void success(String message) { + + success(message, (Object[]) null); + } + + /** + * Should be called to end this {@link Step} {@link #getSuccess() successfully}. May be called only once. + * + * @param message the explicit message to log as success. + * @param args the optional arguments to fill as placeholder into the {@code message}. + */ + void success(String message, Object... args); + + /** + * Ensures this {@link Step} is properly ended. Has to be called from a finally block. + */ + void end(); + + /** + * Should be called to end this {@link Step} as {@link #isFailure() failure} with an explicit error message. May be + * called only once. + * + * @param message the explicit message to log as error. + */ + default void error(String message) { + + error(null, message); + } + + /** + * Should be called to end this {@link Step} as {@link #isFailure() failure} with an explicit error message and/or + * {@link Throwable exception}. May be called only once. + * + * @param message the explicit message to log as error. + * @param args the optional arguments to fill as placeholder into the {@code message}. + */ + default void error(String message, Object... args) { + + error(null, message, args); + } + + /** + * Should be called to end this {@link Step} as {@link #isFailure() failure} with an explicit error message and/or + * {@link Throwable exception}. May be called only once. + * + * @param error the catched {@link Throwable}. + */ + default void error(Throwable error) { + + error(error, false); + } + + /** + * Should be called to end this {@link Step} as {@link #isFailure() failure} with an explicit error message and/or + * {@link Throwable exception}. May be called only once. + * + * @param error the catched {@link Throwable}. + * @param suppress to suppress the error logging (if error will be rethrown and duplicated error messages shall be + * avoided). + */ + default void error(Throwable error, boolean suppress) { + + assert (error != null); + error(error, suppress, null, (Object[]) null); + } + + /** + * Should be called to end this {@link Step} as {@link #isFailure() failure} with an explicit error message and/or + * {@link Throwable exception}. May be called only once. + * + * @param error the catched {@link Throwable}. May be {@code null} if only a {@code message} is provided. + * @param message the explicit message to log as error. + */ + default void error(Throwable error, String message) { + + error(error, message, (Object[]) null); + } + + /** + * Should be called to end this {@link Step} as {@link #isFailure() failure} with an explicit error message and/or + * {@link Throwable exception}. May be called only once. + * + * @param error the catched {@link Throwable}. May be {@code null} if only a {@code message} is provided. + * @param message the explicit message to log as error. + * @param args the optional arguments to fill as placeholder into the {@code message}. + */ + default void error(Throwable error, String message, Object... args) { + + error(error, false, message, args); + } + + /** + * Should be called to end this {@link Step} as {@link #isFailure() failure} with an explicit error message and/or + * {@link Throwable exception}. May be called only once. + * + * @param error the catched {@link Throwable}. May be {@code null} if only a {@code message} is provided. + * @param suppress to suppress the error logging (if error will be rethrown and duplicated error messages shall be + * avoided). + * @param message the explicit message to log as error. + * @param args the optional arguments to fill as placeholder into the {@code message}. + */ + void error(Throwable error, boolean suppress, String message, Object... args); + + /** + * @return the parent {@link Step} or {@code null} if there is no parent. + */ + Step getParent(); + + /** + * @param i the index of the requested parameter. Should be in the range from {@code 0} to + * {@link #getParameterCount()}-1. + * @return the parameter at the given index {@code i} or {@code null} if no such parameter exists. + */ + Object getParameter(int i); + + /** + * @return the number of {@link #getParameter(int) parameters}. + */ + int getParameterCount(); + + /** + * @param stepCode the {@link Runnable} to {@link Runnable#run() execute} for this {@link Step}. + */ + default void run(Runnable stepCode) { + + try { + stepCode.run(); + if (getSuccess() == null) { + success(); + } + } catch (RuntimeException | Error e) { + error(e); + throw e; + } finally { + end(); + } + } + + /** + * @param stepCode the {@link Callable} to {@link Callable#call() execute} for this {@link Step}. + * @param type of the return value. + * @return the value returned from {@link Callable#call()}. + */ + default R call(Callable stepCode) { + + try { + R result = stepCode.call(); + if (getSuccess() == null) { + success(); + } + return result; + } catch (Throwable e) { + error(e); + if (e instanceof RuntimeException re) { + throw re; + } else if (e instanceof Error error) { + throw error; + } else { + throw new IllegalStateException(e); + } + } finally { + end(); + } + } + } \ No newline at end of file diff --git a/cli/src/main/java/com/devonfw/tools/ide/step/StepImpl.java b/cli/src/main/java/com/devonfw/tools/ide/step/StepImpl.java index a8b8ad523..a0745faf8 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/step/StepImpl.java +++ b/cli/src/main/java/com/devonfw/tools/ide/step/StepImpl.java @@ -1,295 +1,295 @@ -package com.devonfw.tools.ide.step; - -import com.devonfw.tools.ide.context.AbstractIdeContext; -import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.log.IdeSubLogger; - -import java.time.Duration; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * Regular implementation of {@link Step}. - */ -public final class StepImpl implements Step { - - private final AbstractIdeContext context; - - private final StepImpl parent; - - private final String name; - - private final Object[] params; - - private final List children; - - private final long start; - - private final boolean silent; - - private Boolean success; - - private String errorMessage; - - private long duration; - - /** - * Creates and starts a new {@link StepImpl}. - * - * @param context the {@link IdeContext}. - * @param parent the {@link #getParent() parent step}. - * @param name the {@link #getName() step name}. - * @param silent the {@link #isSilent() silent flag}. - * @param params the parameters. Should have reasonable {@link Object#toString() string representations}. - */ - public StepImpl(AbstractIdeContext context, StepImpl parent, String name, boolean silent, Object... params) { - - super(); - this.context = context; - this.parent = parent; - this.name = name; - this.params = params; - this.silent = silent; - this.children = new ArrayList<>(); - this.start = System.currentTimeMillis(); - if (parent != null) { - parent.children.add(this); - } - if (params.length == 0) { - this.context.trace("Starting step {}...", name); - } else { - this.context.trace("Starting step {} with params {}...", name, Arrays.toString(params)); - } - if (!this.silent) { - this.context.step("Start: {}", name); - } - } - - @Override - public StepImpl getParent() { - - return this.parent; - } - - @Override - public String getName() { - - return this.name; - } - - @Override - public Object getParameter(int i) { - - if ((i < 0) || (i >= this.params.length)) { - return null; - } - return this.params[i]; - } - - @Override - public int getParameterCount() { - - return this.params.length; - } - - @Override - public boolean isSilent() { - - return this.silent; - } - - @Override - public long getDuration() { - - return this.duration; - } - - @Override - public Boolean getSuccess() { - - return this.success; - } - - @Override - public void success(String message, Object... args) { - - end(Boolean.TRUE, null, false, message, args); - } - - @Override - public void error(Throwable error, boolean suppress, String message, Object... args) { - - end(Boolean.FALSE, error, suppress, message, args); - } - - @Override - public void end() { - - end(null, null, false, null, null); - } - - private void end(Boolean newSuccess, Throwable error, boolean suppress, String message, Object[] args) { - - boolean firstCallOfEnd = (this.success == null); - if (!firstCallOfEnd) { - assert (this.duration > 0); - if (newSuccess != null) { - this.context.warning("Step '{}' already ended with {} and now ended again with {}.", this.name, this.success, - newSuccess); - } else { - return; - } - } - long delay = System.currentTimeMillis() - this.start; - if (delay == 0) { - delay = 1; - } - if (newSuccess == null) { - newSuccess = Boolean.FALSE; - } - if (this.success != Boolean.FALSE) { // never allow a failed step to change to success - this.duration = delay; - this.success = newSuccess; - } - if (newSuccess.booleanValue()) { - assert (error == null); - if (message != null) { - this.context.success(message, args); - } else if (!this.silent) { - this.context.success(this.name); - } - this.context.debug("Step '{}' ended successfully.", this.name); - } else { - IdeSubLogger logger; - if ((message != null) || (error != null)) { - if (suppress) { - if (error != null) { - this.errorMessage = error.toString(); - } else { - this.errorMessage = message; - } - } else { - this.errorMessage = this.context.error().log(error, message, args); - } - logger = this.context.debug(); - } else { - logger = this.context.info(); - } - logger.log("Step '{}' ended with failure.", this.name); - } - if (firstCallOfEnd) { - this.context.endStep(this); - } - } - - /** - * Logs the summary of this {@link Step}. Should typically only be called on the top-level {@link Step}. - * - * @param suppressSuccess - {@code true} to suppress the success message, {@code false} otherwise. - */ - public void logSummary(boolean suppressSuccess) { - - if (this.context.trace().isEnabled()) { - this.context.trace(toString()); - } - if (this.context.isQuietMode()) { - return; - } - StepSummary summary = new StepSummary(); - logErrorSummary(0, summary); - if (summary.getError() == 0) { - if (!suppressSuccess) { - this.context.success("Successfully completed {}", getNameWithParams()); - } - } else { - this.context.error(summary.toString()); - } - } - - private void logErrorSummary(int depth, StepSummary summary) { - - boolean failure = isFailure(); - summary.add(failure); - if (failure) { - this.context.error("{}Step '{}' failed: {}", getIndent(depth), getNameWithParams(), this.errorMessage); - } - depth++; - for (StepImpl child : this.children) { - child.logErrorSummary(depth, summary); - } - } - - private String getNameWithParams() { - - if ((this.params == null) || (this.params.length == 0)) { - return this.name; - } - StringBuilder sb = new StringBuilder(this.name.length() + 3 + this.params.length * 6); - getNameWithParams(sb); - return sb.toString(); - } - - private void getNameWithParams(StringBuilder sb) { - - sb.append(this.name); - sb.append(" ("); - String seperator = ""; - if (this.params != null) { - for (Object param : this.params) { - sb.append(seperator); - sb.append(param); - seperator = ","; - } - } - sb.append(')'); - } - - private void append(int depth, long totalDuration, long parentDuration, StringBuilder sb) { - - // indent - sb.append(getIndent(depth)); - getNameWithParams(sb); - sb.append(' '); - if (this.success == null) { - sb.append("is still running or was not properly ended due to programming error not using finally block "); - } else { - if (this.success.booleanValue()) { - sb.append("succeeded after "); - } else { - sb.append("failed after "); - } - sb.append(Duration.ofMillis(this.duration)); - } - if (this.duration < totalDuration) { - sb.append(" "); - double percentageBase = this.duration * 100; - double totalPercentage = percentageBase / totalDuration; - sb.append(totalPercentage); - sb.append("% of total "); - if (parentDuration < totalDuration) { - double parentPercentage = percentageBase / parentDuration; - sb.append(parentPercentage); - sb.append("% of parent"); - } - } - sb.append('\n'); - int childDepth = depth + 1; - for (StepImpl child : this.children) { - child.append(childDepth, totalDuration, this.duration, sb); - } - } - - private String getIndent(int depth) { - - return " ".repeat(depth); - } - - @Override - public String toString() { - - StringBuilder sb = new StringBuilder(4096); - append(0, this.duration, this.duration, sb); - return sb.toString(); - } -} +package com.devonfw.tools.ide.step; + +import com.devonfw.tools.ide.context.AbstractIdeContext; +import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.log.IdeSubLogger; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Regular implementation of {@link Step}. + */ +public final class StepImpl implements Step { + + private final AbstractIdeContext context; + + private final StepImpl parent; + + private final String name; + + private final Object[] params; + + private final List children; + + private final long start; + + private final boolean silent; + + private Boolean success; + + private String errorMessage; + + private long duration; + + /** + * Creates and starts a new {@link StepImpl}. + * + * @param context the {@link IdeContext}. + * @param parent the {@link #getParent() parent step}. + * @param name the {@link #getName() step name}. + * @param silent the {@link #isSilent() silent flag}. + * @param params the parameters. Should have reasonable {@link Object#toString() string representations}. + */ + public StepImpl(AbstractIdeContext context, StepImpl parent, String name, boolean silent, Object... params) { + + super(); + this.context = context; + this.parent = parent; + this.name = name; + this.params = params; + this.silent = silent; + this.children = new ArrayList<>(); + this.start = System.currentTimeMillis(); + if (parent != null) { + parent.children.add(this); + } + if (params.length == 0) { + this.context.trace("Starting step {}...", name); + } else { + this.context.trace("Starting step {} with params {}...", name, Arrays.toString(params)); + } + if (!this.silent) { + this.context.step("Start: {}", name); + } + } + + @Override + public StepImpl getParent() { + + return this.parent; + } + + @Override + public String getName() { + + return this.name; + } + + @Override + public Object getParameter(int i) { + + if ((i < 0) || (i >= this.params.length)) { + return null; + } + return this.params[i]; + } + + @Override + public int getParameterCount() { + + return this.params.length; + } + + @Override + public boolean isSilent() { + + return this.silent; + } + + @Override + public long getDuration() { + + return this.duration; + } + + @Override + public Boolean getSuccess() { + + return this.success; + } + + @Override + public void success(String message, Object... args) { + + end(Boolean.TRUE, null, false, message, args); + } + + @Override + public void error(Throwable error, boolean suppress, String message, Object... args) { + + end(Boolean.FALSE, error, suppress, message, args); + } + + @Override + public void end() { + + end(null, null, false, null, null); + } + + private void end(Boolean newSuccess, Throwable error, boolean suppress, String message, Object[] args) { + + boolean firstCallOfEnd = (this.success == null); + if (!firstCallOfEnd) { + assert (this.duration > 0); + if (newSuccess != null) { + this.context.warning("Step '{}' already ended with {} and now ended again with {}.", this.name, this.success, + newSuccess); + } else { + return; + } + } + long delay = System.currentTimeMillis() - this.start; + if (delay == 0) { + delay = 1; + } + if (newSuccess == null) { + newSuccess = Boolean.FALSE; + } + if (this.success != Boolean.FALSE) { // never allow a failed step to change to success + this.duration = delay; + this.success = newSuccess; + } + if (newSuccess.booleanValue()) { + assert (error == null); + if (message != null) { + this.context.success(message, args); + } else if (!this.silent) { + this.context.success(this.name); + } + this.context.debug("Step '{}' ended successfully.", this.name); + } else { + IdeSubLogger logger; + if ((message != null) || (error != null)) { + if (suppress) { + if (error != null) { + this.errorMessage = error.toString(); + } else { + this.errorMessage = message; + } + } else { + this.errorMessage = this.context.error().log(error, message, args); + } + logger = this.context.debug(); + } else { + logger = this.context.info(); + } + logger.log("Step '{}' ended with failure.", this.name); + } + if (firstCallOfEnd) { + this.context.endStep(this); + } + } + + /** + * Logs the summary of this {@link Step}. Should typically only be called on the top-level {@link Step}. + * + * @param suppressSuccess - {@code true} to suppress the success message, {@code false} otherwise. + */ + public void logSummary(boolean suppressSuccess) { + + if (this.context.trace().isEnabled()) { + this.context.trace(toString()); + } + if (this.context.isQuietMode()) { + return; + } + StepSummary summary = new StepSummary(); + logErrorSummary(0, summary); + if (summary.getError() == 0) { + if (!suppressSuccess) { + this.context.success("Successfully completed {}", getNameWithParams()); + } + } else { + this.context.error(summary.toString()); + } + } + + private void logErrorSummary(int depth, StepSummary summary) { + + boolean failure = isFailure(); + summary.add(failure); + if (failure) { + this.context.error("{}Step '{}' failed: {}", getIndent(depth), getNameWithParams(), this.errorMessage); + } + depth++; + for (StepImpl child : this.children) { + child.logErrorSummary(depth, summary); + } + } + + private String getNameWithParams() { + + if ((this.params == null) || (this.params.length == 0)) { + return this.name; + } + StringBuilder sb = new StringBuilder(this.name.length() + 3 + this.params.length * 6); + getNameWithParams(sb); + return sb.toString(); + } + + private void getNameWithParams(StringBuilder sb) { + + sb.append(this.name); + sb.append(" ("); + String seperator = ""; + if (this.params != null) { + for (Object param : this.params) { + sb.append(seperator); + sb.append(param); + seperator = ","; + } + } + sb.append(')'); + } + + private void append(int depth, long totalDuration, long parentDuration, StringBuilder sb) { + + // indent + sb.append(getIndent(depth)); + getNameWithParams(sb); + sb.append(' '); + if (this.success == null) { + sb.append("is still running or was not properly ended due to programming error not using finally block "); + } else { + if (this.success.booleanValue()) { + sb.append("succeeded after "); + } else { + sb.append("failed after "); + } + sb.append(Duration.ofMillis(this.duration)); + } + if (this.duration < totalDuration) { + sb.append(" "); + double percentageBase = this.duration * 100; + double totalPercentage = percentageBase / totalDuration; + sb.append(totalPercentage); + sb.append("% of total "); + if (parentDuration < totalDuration) { + double parentPercentage = percentageBase / parentDuration; + sb.append(parentPercentage); + sb.append("% of parent"); + } + } + sb.append('\n'); + int childDepth = depth + 1; + for (StepImpl child : this.children) { + child.append(childDepth, totalDuration, this.duration, sb); + } + } + + private String getIndent(int depth) { + + return " ".repeat(depth); + } + + @Override + public String toString() { + + StringBuilder sb = new StringBuilder(4096); + append(0, this.duration, this.duration, sb); + return sb.toString(); + } +} diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/PackageManagerCommand.java b/cli/src/main/java/com/devonfw/tools/ide/tool/PackageManagerCommand.java index d39516ac9..6c687e969 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/PackageManagerCommand.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/PackageManagerCommand.java @@ -1,26 +1,26 @@ -package com.devonfw.tools.ide.tool; - -import java.util.List; - -/** - * Represents a command to be executed by a package manager. Each command consists of a {@link PackageManager} and a - * list of commands to be executed by that package manager. - * - * @param packageManager The package manager associated with this command. - * @param commands The list of commands to be executed by the package manager. - */ -public record PackageManagerCommand(PackageManager packageManager, List commands) { - - /** - * Constructs a {@code PackageManagerCommand} based on the provided command string. The package manager is retrieved - * from the command string using {@link PackageManager#extractPackageManager(String)}. - * - * @param command The command string. - * @return A {@code PackageManagerCommand} based on the provided command string. - */ - public static PackageManagerCommand of(String command) { - - PackageManager pm = PackageManager.extractPackageManager(command); - return new PackageManagerCommand(pm, List.of(command)); - } -} +package com.devonfw.tools.ide.tool; + +import java.util.List; + +/** + * Represents a command to be executed by a package manager. Each command consists of a {@link PackageManager} and a + * list of commands to be executed by that package manager. + * + * @param packageManager The package manager associated with this command. + * @param commands The list of commands to be executed by the package manager. + */ +public record PackageManagerCommand(PackageManager packageManager, List commands) { + + /** + * Constructs a {@code PackageManagerCommand} based on the provided command string. The package manager is retrieved + * from the command string using {@link PackageManager#extractPackageManager(String)}. + * + * @param command The command string. + * @return A {@code PackageManagerCommand} based on the provided command string. + */ + public static PackageManagerCommand of(String command) { + + PackageManager pm = PackageManager.extractPackageManager(command); + return new PackageManagerCommand(pm, List.of(command)); + } +} diff --git a/cli/src/main/java/com/devonfw/tools/ide/variable/IdeVariables.java b/cli/src/main/java/com/devonfw/tools/ide/variable/IdeVariables.java index 9e6259a82..6c01c1ad1 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/variable/IdeVariables.java +++ b/cli/src/main/java/com/devonfw/tools/ide/variable/IdeVariables.java @@ -1,75 +1,75 @@ -package com.devonfw.tools.ide.variable; - -import java.util.Collection; -import java.util.List; - -/** - * Interface (mis)used to define all the available variables. - */ -public interface IdeVariables { - - /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getIdeHome() IDE_HOME}. */ - VariableDefinitionPath IDE_HOME = new VariableDefinitionPath("IDE_HOME", "DEVON_IDE_HOME", c -> c.getIdeHome(), true); - - /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getIdeRoot() IDE_ROOT}. */ - VariableDefinitionPath IDE_ROOT = new VariableDefinitionPath("IDE_ROOT", null, c -> c.getIdeRoot()); - - /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getUserHome() HOME}. */ - VariableDefinitionPath HOME = new VariableDefinitionPath("HOME", null, c -> c.getUserHome(), true); - - /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getWorkspaceName() WORKSPACE}. */ - VariableDefinitionString WORKSPACE = new VariableDefinitionString("WORKSPACE", null, c -> c.getWorkspaceName(), true); - - /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getPath() PATH}. */ - VariableDefinitionSystemPath PATH = new VariableDefinitionSystemPath("PATH", null, c -> c.getPath(), true, true); - - /** - * {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getWorkspacePath() WORKSPACE_PATH}. - */ - VariableDefinitionPath WORKSPACE_PATH = new VariableDefinitionPath("WORKSPACE_PATH", null, c -> c.getWorkspacePath(), true); - - /** {@link VariableDefinition} for list of tools to install by default. */ - VariableDefinitionStringList IDE_TOOLS = new VariableDefinitionStringList("IDE_TOOLS", "DEVON_IDE_TOOLS", c -> List.of("mvn", "npm")); - - /** {@link VariableDefinition} for list of IDE tools to create start scripts for. */ - VariableDefinitionStringList CREATE_START_SCRIPTS = new VariableDefinitionStringList("CREATE_START_SCRIPTS", "DEVON_CREATE_START_SCRIPTS"); - - /** {@link VariableDefinition} for minimum IDE product version. */ - // TODO define initial IDEasy version as default value - VariableDefinitionVersion IDE_MIN_VERSION = new VariableDefinitionVersion("IDE_MIN_VERSION", "DEVON_IDE_MIN_VERSION"); - - /** {@link VariableDefinition} for version of maven (mvn). */ - VariableDefinitionVersion MVN_VERSION = new VariableDefinitionVersion("MVN_VERSION", "MAVEN_VERSION"); - - /** {@link VariableDefinition} arguments for maven to set the m2 repo location. */ - VariableDefinitionString MAVEN_ARGS = new VariableDefinitionString("MAVEN_ARGS", null, c -> c.getMavenArgs(), false, true); - - /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getWorkspaceName() WORKSPACE}. */ - VariableDefinitionString DOCKER_EDITION = new VariableDefinitionString("DOCKER_EDITION", null, c -> "rancher"); - - /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getWorkspaceName() WORKSPACE}. */ - VariableDefinitionString GRAALVM_EDITION = new VariableDefinitionString("GRAALVM_EDITION", null, c -> "community"); - - /** {@link VariableDefinition} for options of jasypt */ - VariableDefinitionString JASYPT_OPTS = new VariableDefinitionString("JASYPT_OPTS", null, - c -> "algorithm=PBEWITHHMACSHA512ANDAES_256 ivGeneratorClassName=org.jasypt.iv.RandomIvGenerator"); - - /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getProjectName() PROJECT_NAME}. */ - VariableDefinitionString PROJECT_NAME = new VariableDefinitionString("PROJECT_NAME", null, c -> c.getProjectName()); - - /** A {@link Collection} with all pre-defined {@link VariableDefinition}s. */ - Collection> VARIABLES = List.of(PATH, HOME, WORKSPACE_PATH, IDE_HOME, IDE_ROOT, WORKSPACE, IDE_TOOLS, CREATE_START_SCRIPTS, - IDE_MIN_VERSION, MVN_VERSION, DOCKER_EDITION, GRAALVM_EDITION, JASYPT_OPTS, MAVEN_ARGS, PROJECT_NAME); - - /** - * @param name the name of the requested {@link VariableDefinition}. - * @return the {@link VariableDefinition} for the given {@code name} or {@code null} if not defined. - * @see VariableDefinition#getName() - * @see VariableDefinition#getLegacyName() - */ - static VariableDefinition get(String name) { - - return IdeVariablesList.get(name); - } - -} +package com.devonfw.tools.ide.variable; + +import java.util.Collection; +import java.util.List; + +/** + * Interface (mis)used to define all the available variables. + */ +public interface IdeVariables { + + /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getIdeHome() IDE_HOME}. */ + VariableDefinitionPath IDE_HOME = new VariableDefinitionPath("IDE_HOME", "DEVON_IDE_HOME", c -> c.getIdeHome(), true); + + /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getIdeRoot() IDE_ROOT}. */ + VariableDefinitionPath IDE_ROOT = new VariableDefinitionPath("IDE_ROOT", null, c -> c.getIdeRoot()); + + /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getUserHome() HOME}. */ + VariableDefinitionPath HOME = new VariableDefinitionPath("HOME", null, c -> c.getUserHome(), true); + + /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getWorkspaceName() WORKSPACE}. */ + VariableDefinitionString WORKSPACE = new VariableDefinitionString("WORKSPACE", null, c -> c.getWorkspaceName(), true); + + /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getPath() PATH}. */ + VariableDefinitionSystemPath PATH = new VariableDefinitionSystemPath("PATH", null, c -> c.getPath(), true, true); + + /** + * {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getWorkspacePath() WORKSPACE_PATH}. + */ + VariableDefinitionPath WORKSPACE_PATH = new VariableDefinitionPath("WORKSPACE_PATH", null, c -> c.getWorkspacePath(), true); + + /** {@link VariableDefinition} for list of tools to install by default. */ + VariableDefinitionStringList IDE_TOOLS = new VariableDefinitionStringList("IDE_TOOLS", "DEVON_IDE_TOOLS", c -> List.of("mvn", "npm")); + + /** {@link VariableDefinition} for list of IDE tools to create start scripts for. */ + VariableDefinitionStringList CREATE_START_SCRIPTS = new VariableDefinitionStringList("CREATE_START_SCRIPTS", "DEVON_CREATE_START_SCRIPTS"); + + /** {@link VariableDefinition} for minimum IDE product version. */ + // TODO define initial IDEasy version as default value + VariableDefinitionVersion IDE_MIN_VERSION = new VariableDefinitionVersion("IDE_MIN_VERSION", "DEVON_IDE_MIN_VERSION"); + + /** {@link VariableDefinition} for version of maven (mvn). */ + VariableDefinitionVersion MVN_VERSION = new VariableDefinitionVersion("MVN_VERSION", "MAVEN_VERSION"); + + /** {@link VariableDefinition} arguments for maven to set the m2 repo location. */ + VariableDefinitionString MAVEN_ARGS = new VariableDefinitionString("MAVEN_ARGS", null, c -> c.getMavenArgs(), false, true); + + /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getWorkspaceName() WORKSPACE}. */ + VariableDefinitionString DOCKER_EDITION = new VariableDefinitionString("DOCKER_EDITION", null, c -> "rancher"); + + /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getWorkspaceName() WORKSPACE}. */ + VariableDefinitionString GRAALVM_EDITION = new VariableDefinitionString("GRAALVM_EDITION", null, c -> "community"); + + /** {@link VariableDefinition} for options of jasypt */ + VariableDefinitionString JASYPT_OPTS = new VariableDefinitionString("JASYPT_OPTS", null, + c -> "algorithm=PBEWITHHMACSHA512ANDAES_256 ivGeneratorClassName=org.jasypt.iv.RandomIvGenerator"); + + /** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getProjectName() PROJECT_NAME}. */ + VariableDefinitionString PROJECT_NAME = new VariableDefinitionString("PROJECT_NAME", null, c -> c.getProjectName()); + + /** A {@link Collection} with all pre-defined {@link VariableDefinition}s. */ + Collection> VARIABLES = List.of(PATH, HOME, WORKSPACE_PATH, IDE_HOME, IDE_ROOT, WORKSPACE, IDE_TOOLS, CREATE_START_SCRIPTS, + IDE_MIN_VERSION, MVN_VERSION, DOCKER_EDITION, GRAALVM_EDITION, JASYPT_OPTS, MAVEN_ARGS, PROJECT_NAME); + + /** + * @param name the name of the requested {@link VariableDefinition}. + * @return the {@link VariableDefinition} for the given {@code name} or {@code null} if not defined. + * @see VariableDefinition#getName() + * @see VariableDefinition#getLegacyName() + */ + static VariableDefinition get(String name) { + + return IdeVariablesList.get(name); + } + +} diff --git a/cli/src/test/java/com/devonfw/tools/ide/log/IdeSlf4jLogger.java b/cli/src/test/java/com/devonfw/tools/ide/log/IdeSlf4jLogger.java index 102d40a8e..efd06b047 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/log/IdeSlf4jLogger.java +++ b/cli/src/test/java/com/devonfw/tools/ide/log/IdeSlf4jLogger.java @@ -1,77 +1,77 @@ -package com.devonfw.tools.ide.log; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.slf4j.event.Level; -import org.slf4j.spi.LoggingEventBuilder; - -/** - * Implementation of {@link IdeSubLogger} for testing that delegates to slf4j. - */ -public class IdeSlf4jLogger extends AbstractIdeSubLogger { - - private static final Logger LOG = LoggerFactory.getLogger(IdeSlf4jLogger.class); - - private final Level logLevel; - - /** - * The constructor. - * - * @param level the {@link #getLevel() log-level}. - */ - public IdeSlf4jLogger(IdeLogLevel level) { - - super(level); - this.logLevel = switch (level) { - case TRACE -> Level.TRACE; - case DEBUG -> Level.DEBUG; - case INFO, STEP, INTERACTION, SUCCESS -> Level.INFO; - case WARNING -> Level.WARN; - case ERROR -> Level.ERROR; - default -> throw new IllegalArgumentException("" + level); - }; - } - - @Override - public String log(Throwable error, String message, Object... args) { - - if ((message == null) && (error != null)) { - message = error.getMessage(); - if (message == null) { - message = error.toString(); - } - } - String msg = message; - if ((this.level == IdeLogLevel.STEP) || (this.level == IdeLogLevel.INTERACTION) - || (this.level == IdeLogLevel.SUCCESS)) { - msg = this.level.name() + ":" + message; - } - LoggingEventBuilder builder = LOG.atLevel(this.logLevel); - if (error != null) { - builder.setCause(error); - } - if (args == null) { - builder.log(msg); - } else { - builder.log(msg, args); - } - if (message == null) { - if (error == null) { - return null; - } else { - return error.toString(); - } - } else if (args == null) { - return message; - } else { - return compose(message, args); - } - } - - @Override - public boolean isEnabled() { - - return LOG.isEnabledForLevel(this.logLevel); - } - -} +package com.devonfw.tools.ide.log; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.event.Level; +import org.slf4j.spi.LoggingEventBuilder; + +/** + * Implementation of {@link IdeSubLogger} for testing that delegates to slf4j. + */ +public class IdeSlf4jLogger extends AbstractIdeSubLogger { + + private static final Logger LOG = LoggerFactory.getLogger(IdeSlf4jLogger.class); + + private final Level logLevel; + + /** + * The constructor. + * + * @param level the {@link #getLevel() log-level}. + */ + public IdeSlf4jLogger(IdeLogLevel level) { + + super(level); + this.logLevel = switch (level) { + case TRACE -> Level.TRACE; + case DEBUG -> Level.DEBUG; + case INFO, STEP, INTERACTION, SUCCESS -> Level.INFO; + case WARNING -> Level.WARN; + case ERROR -> Level.ERROR; + default -> throw new IllegalArgumentException("" + level); + }; + } + + @Override + public String log(Throwable error, String message, Object... args) { + + if ((message == null) && (error != null)) { + message = error.getMessage(); + if (message == null) { + message = error.toString(); + } + } + String msg = message; + if ((this.level == IdeLogLevel.STEP) || (this.level == IdeLogLevel.INTERACTION) + || (this.level == IdeLogLevel.SUCCESS)) { + msg = this.level.name() + ":" + message; + } + LoggingEventBuilder builder = LOG.atLevel(this.logLevel); + if (error != null) { + builder.setCause(error); + } + if (args == null) { + builder.log(msg); + } else { + builder.log(msg, args); + } + if (message == null) { + if (error == null) { + return null; + } else { + return error.toString(); + } + } else if (args == null) { + return message; + } else { + return compose(message, args); + } + } + + @Override + public boolean isEnabled() { + + return LOG.isEnabledForLevel(this.logLevel); + } + +} diff --git a/cli/src/test/java/com/devonfw/tools/ide/step/StepTest.java b/cli/src/test/java/com/devonfw/tools/ide/step/StepTest.java index 132cc869f..8477a9683 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/step/StepTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/step/StepTest.java @@ -1,133 +1,133 @@ -package com.devonfw.tools.ide.step; - -import com.devonfw.tools.ide.context.AbstractIdeContextTest; -import com.devonfw.tools.ide.context.IdeTestContext; -import com.devonfw.tools.ide.log.IdeLogLevel; -import org.junit.jupiter.api.Test; - -/** - * Test of {@link Step}. - */ -public class StepTest extends AbstractIdeContextTest { - - @Test - public void testValidUsageSuccess() { - - // arrage - IdeTestContext context = newContext(PROJECT_BASIC, "project", false); - // act - Step step = context.newStep("Test-Step"); - try { - step.success("The Test-Step succeeded as expected"); - } finally { - step.end(); - } - // assert - assertThat(step.getSuccess()).isTrue(); - assertThat(step.getDuration()).isPositive(); - assertLogMessage(context, IdeLogLevel.TRACE, "Starting step Test-Step..."); - assertLogMessage(context, IdeLogLevel.STEP, "Start: Test-Step"); - assertLogMessage(context, IdeLogLevel.SUCCESS, "The Test-Step succeeded as expected"); - assertLogMessage(context, IdeLogLevel.DEBUG, "Step 'Test-Step' ended successfully."); - } - - @Test - public void testValidUsageSuccessSilent() { - - // arrage - IdeTestContext context = newContext(PROJECT_BASIC, "project", false); - // act - Step step = context.newStep(true, "Test-Step", "arg1", "arg2"); - try { - step.success(); - } finally { - step.end(); - } - // assert - assertThat(step.getSuccess()).isTrue(); - assertThat(step.getDuration()).isPositive(); - assertThat(step.getParameterCount()).isEqualTo(2); - assertThat(step.getParameter(0)).isEqualTo("arg1"); - assertThat(step.getParameter(1)).isEqualTo("arg2"); - assertThat(step.getParameter(2)).isNull(); - assertLogMessage(context, IdeLogLevel.TRACE, "Starting step Test-Step with params [arg1, arg2]..."); - assertNoLogMessage(context, IdeLogLevel.STEP, "Start: Test-Step"); - assertNoLogMessage(context, IdeLogLevel.SUCCESS, "Test-Step", true); - assertLogMessage(context, IdeLogLevel.DEBUG, "Step 'Test-Step' ended successfully."); - } - - @Test - public void testValidUsageError() { - - // arrage - IdeTestContext context = newContext(PROJECT_BASIC, "project", false); - // act - Step step = context.newStep("Test-Step"); - try { - step.error("The Test-Step failed as expected"); - } finally { - step.end(); - } - assertThat(step.getSuccess()).isFalse(); - assertThat(step.getDuration()).isPositive(); - // assert - assertLogMessage(context, IdeLogLevel.TRACE, "Starting step Test-Step..."); - assertLogMessage(context, IdeLogLevel.STEP, "Start: Test-Step"); - assertLogMessage(context, IdeLogLevel.ERROR, "The Test-Step failed as expected"); - assertLogMessage(context, IdeLogLevel.DEBUG, "Step 'Test-Step' ended with failure."); - } - - @Test - public void testInvalidUsageSuccessError() { - - // arrage - IdeTestContext context = newContext(PROJECT_BASIC, "project", false); - // act - Step step = context.newStep("Test-Step"); - try { - step.success("The Test-Step succeeded as expected"); - throw new IllegalStateException("unexpected situation!"); - } catch (IllegalStateException e) { - step.error(e); - } finally { - step.end(); - } - assertThat(step.getSuccess()).isFalse(); - assertThat(step.getDuration()).isPositive(); - // assert - assertLogMessage(context, IdeLogLevel.TRACE, "Starting step Test-Step..."); - assertLogMessage(context, IdeLogLevel.STEP, "Start: Test-Step"); - assertLogMessage(context, IdeLogLevel.WARNING, - "Step 'Test-Step' already ended with true and now ended again with false."); - assertLogMessage(context, IdeLogLevel.ERROR, "unexpected situation!"); - assertLogMessage(context, IdeLogLevel.DEBUG, "Step 'Test-Step' ended with failure."); - } - - @Test - public void testInvalidUsageErrorSuccess() { - - // arrage - IdeTestContext context = newContext(PROJECT_BASIC, "project", false); - // act - Step step = context.newStep("Test-Step"); - try { - step.error("The Test-Step failed as expected"); - // WOW this is really inconsistent and hopefully never happens elsewhere - step.success("The Test-Step succeeded as expected"); - } finally { - step.end(); - } - assertThat(step.getSuccess()).isFalse(); - assertThat(step.getDuration()).isPositive(); - // assert - assertLogMessage(context, IdeLogLevel.TRACE, "Starting step Test-Step..."); - assertLogMessage(context, IdeLogLevel.STEP, "Start: Test-Step"); - assertLogMessage(context, IdeLogLevel.ERROR, "The Test-Step failed as expected"); - assertLogMessage(context, IdeLogLevel.DEBUG, "Step 'Test-Step' ended with failure."); - assertLogMessage(context, IdeLogLevel.WARNING, - "Step 'Test-Step' already ended with false and now ended again with true."); - assertLogMessage(context, IdeLogLevel.SUCCESS, "The Test-Step succeeded as expected"); - assertLogMessage(context, IdeLogLevel.DEBUG, "Step 'Test-Step' ended successfully."); - } - -} +package com.devonfw.tools.ide.step; + +import com.devonfw.tools.ide.context.AbstractIdeContextTest; +import com.devonfw.tools.ide.context.IdeTestContext; +import com.devonfw.tools.ide.log.IdeLogLevel; +import org.junit.jupiter.api.Test; + +/** + * Test of {@link Step}. + */ +public class StepTest extends AbstractIdeContextTest { + + @Test + public void testValidUsageSuccess() { + + // arrage + IdeTestContext context = newContext(PROJECT_BASIC, "project", false); + // act + Step step = context.newStep("Test-Step"); + try { + step.success("The Test-Step succeeded as expected"); + } finally { + step.end(); + } + // assert + assertThat(step.getSuccess()).isTrue(); + assertThat(step.getDuration()).isPositive(); + assertLogMessage(context, IdeLogLevel.TRACE, "Starting step Test-Step..."); + assertLogMessage(context, IdeLogLevel.STEP, "Start: Test-Step"); + assertLogMessage(context, IdeLogLevel.SUCCESS, "The Test-Step succeeded as expected"); + assertLogMessage(context, IdeLogLevel.DEBUG, "Step 'Test-Step' ended successfully."); + } + + @Test + public void testValidUsageSuccessSilent() { + + // arrage + IdeTestContext context = newContext(PROJECT_BASIC, "project", false); + // act + Step step = context.newStep(true, "Test-Step", "arg1", "arg2"); + try { + step.success(); + } finally { + step.end(); + } + // assert + assertThat(step.getSuccess()).isTrue(); + assertThat(step.getDuration()).isPositive(); + assertThat(step.getParameterCount()).isEqualTo(2); + assertThat(step.getParameter(0)).isEqualTo("arg1"); + assertThat(step.getParameter(1)).isEqualTo("arg2"); + assertThat(step.getParameter(2)).isNull(); + assertLogMessage(context, IdeLogLevel.TRACE, "Starting step Test-Step with params [arg1, arg2]..."); + assertNoLogMessage(context, IdeLogLevel.STEP, "Start: Test-Step"); + assertNoLogMessage(context, IdeLogLevel.SUCCESS, "Test-Step", true); + assertLogMessage(context, IdeLogLevel.DEBUG, "Step 'Test-Step' ended successfully."); + } + + @Test + public void testValidUsageError() { + + // arrage + IdeTestContext context = newContext(PROJECT_BASIC, "project", false); + // act + Step step = context.newStep("Test-Step"); + try { + step.error("The Test-Step failed as expected"); + } finally { + step.end(); + } + assertThat(step.getSuccess()).isFalse(); + assertThat(step.getDuration()).isPositive(); + // assert + assertLogMessage(context, IdeLogLevel.TRACE, "Starting step Test-Step..."); + assertLogMessage(context, IdeLogLevel.STEP, "Start: Test-Step"); + assertLogMessage(context, IdeLogLevel.ERROR, "The Test-Step failed as expected"); + assertLogMessage(context, IdeLogLevel.DEBUG, "Step 'Test-Step' ended with failure."); + } + + @Test + public void testInvalidUsageSuccessError() { + + // arrage + IdeTestContext context = newContext(PROJECT_BASIC, "project", false); + // act + Step step = context.newStep("Test-Step"); + try { + step.success("The Test-Step succeeded as expected"); + throw new IllegalStateException("unexpected situation!"); + } catch (IllegalStateException e) { + step.error(e); + } finally { + step.end(); + } + assertThat(step.getSuccess()).isFalse(); + assertThat(step.getDuration()).isPositive(); + // assert + assertLogMessage(context, IdeLogLevel.TRACE, "Starting step Test-Step..."); + assertLogMessage(context, IdeLogLevel.STEP, "Start: Test-Step"); + assertLogMessage(context, IdeLogLevel.WARNING, + "Step 'Test-Step' already ended with true and now ended again with false."); + assertLogMessage(context, IdeLogLevel.ERROR, "unexpected situation!"); + assertLogMessage(context, IdeLogLevel.DEBUG, "Step 'Test-Step' ended with failure."); + } + + @Test + public void testInvalidUsageErrorSuccess() { + + // arrage + IdeTestContext context = newContext(PROJECT_BASIC, "project", false); + // act + Step step = context.newStep("Test-Step"); + try { + step.error("The Test-Step failed as expected"); + // WOW this is really inconsistent and hopefully never happens elsewhere + step.success("The Test-Step succeeded as expected"); + } finally { + step.end(); + } + assertThat(step.getSuccess()).isFalse(); + assertThat(step.getDuration()).isPositive(); + // assert + assertLogMessage(context, IdeLogLevel.TRACE, "Starting step Test-Step..."); + assertLogMessage(context, IdeLogLevel.STEP, "Start: Test-Step"); + assertLogMessage(context, IdeLogLevel.ERROR, "The Test-Step failed as expected"); + assertLogMessage(context, IdeLogLevel.DEBUG, "Step 'Test-Step' ended with failure."); + assertLogMessage(context, IdeLogLevel.WARNING, + "Step 'Test-Step' already ended with false and now ended again with true."); + assertLogMessage(context, IdeLogLevel.SUCCESS, "The Test-Step succeeded as expected"); + assertLogMessage(context, IdeLogLevel.DEBUG, "Step 'Test-Step' ended successfully."); + } + +} diff --git a/documentation/symlink.adoc b/documentation/symlink.adoc index 738c14c9f..3c1d11886 100644 --- a/documentation/symlink.adoc +++ b/documentation/symlink.adoc @@ -1,22 +1,22 @@ -:toc: -toc::[] - -= Symlink - -The creation of real symbolic links on Windows, requires the user to have according permissions. -In order to grant these permissions to yourself, run `secpol.msc` (`Local Security Policy`) and select `Local Policies/User Rights Assignment` - -1. Right click `Create Symbolic Link`, to open `Properties` and `Add User or Group` -+ -image::images/LocalSecurityPolicy.png[LocalSecurityPolicy] -+ -2. Add your own user account. -To do so you might need to be connected to a VPN depending on the company settings. - -[cols="3,1a,1a,3", frame=none, grid=none] -|=== -| -| image::images/LSPPoperty.png[] -| image::images/LSPAddUser.png[] -| -|=== +:toc: +toc::[] + += Symlink + +The creation of real symbolic links on Windows, requires the user to have according permissions. +In order to grant these permissions to yourself, run `secpol.msc` (`Local Security Policy`) and select `Local Policies/User Rights Assignment` + +1. Right click `Create Symbolic Link`, to open `Properties` and `Add User or Group` ++ +image::images/LocalSecurityPolicy.png[LocalSecurityPolicy] ++ +2. Add your own user account. +To do so you might need to be connected to a VPN depending on the company settings. + +[cols="3,1a,1a,3", frame=none, grid=none] +|=== +| +| image::images/LSPPoperty.png[] +| image::images/LSPAddUser.png[] +| +|=== From f4171e4d163b70e6c62cd42a750b2c4f783c7e01 Mon Sep 17 00:00:00 2001 From: jan-vcapgemini Date: Mon, 22 Apr 2024 18:19:58 +0200 Subject: [PATCH 05/20] #12: added test + resources added parameterized installation test --- .../tool/androidstudio/AndroidStudioTest.java | 48 +++++++++++++++++++ .../android-studio/_ide/urls/readme | 1 + .../project/home/.ide/ide.properties | 0 .../android-studio/project/home/readme | 1 + .../android-studio/project/readme | 1 + .../project/settings/ide.properties | 2 + .../project/workspaces/main/readme | 1 + .../ide-projects/android-studio/readme | 1 + .../default/linux/bin/studio.sh | 2 + .../android-studio/default/mac/bin/studio.sh | 2 + .../repository/java/java/default/bin/java | 2 + .../repository/java/java/default/bin/java.cmd | 2 + 12 files changed, 63 insertions(+) create mode 100644 cli/src/test/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudioTest.java create mode 100644 cli/src/test/resources/ide-projects/android-studio/_ide/urls/readme create mode 100644 cli/src/test/resources/ide-projects/android-studio/project/home/.ide/ide.properties create mode 100644 cli/src/test/resources/ide-projects/android-studio/project/home/readme create mode 100644 cli/src/test/resources/ide-projects/android-studio/project/readme create mode 100644 cli/src/test/resources/ide-projects/android-studio/project/settings/ide.properties create mode 100644 cli/src/test/resources/ide-projects/android-studio/project/workspaces/main/readme create mode 100644 cli/src/test/resources/ide-projects/android-studio/readme create mode 100644 cli/src/test/resources/ide-projects/android-studio/repository/android-studio/android-studio/default/linux/bin/studio.sh create mode 100644 cli/src/test/resources/ide-projects/android-studio/repository/android-studio/android-studio/default/mac/bin/studio.sh create mode 100644 cli/src/test/resources/ide-projects/android-studio/repository/java/java/default/bin/java create mode 100644 cli/src/test/resources/ide-projects/android-studio/repository/java/java/default/bin/java.cmd diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudioTest.java b/cli/src/test/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudioTest.java new file mode 100644 index 000000000..87653a26f --- /dev/null +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudioTest.java @@ -0,0 +1,48 @@ +package com.devonfw.tools.ide.tool.androidstudio; + +import com.devonfw.tools.ide.context.AbstractIdeContextTest; +import com.devonfw.tools.ide.context.IdeTestContext; +import com.devonfw.tools.ide.log.IdeLogLevel; +import com.devonfw.tools.ide.os.SystemInfo; +import com.devonfw.tools.ide.os.SystemInfoMock; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +public class AndroidStudioTest extends AbstractIdeContextTest { + + private static final String PROJECT_ANDROID_STUDIO = "android-studio"; + + private final IdeTestContext context = newContext(PROJECT_ANDROID_STUDIO); + + @ParameterizedTest + @ValueSource(strings = { "windows", "mac", "linux" }) + public void testAndroidStudioInstall(String os) { + // arrange + SystemInfo systemInfo = SystemInfoMock.of(os); + context.setSystemInfo(systemInfo); + IdeTestContext context = newContext(PROJECT_ANDROID_STUDIO); + AndroidStudio commandlet = new AndroidStudio(context); + + // act + commandlet.install(); + + // assert + checkInstallation(context); + } + + private void checkInstallation(IdeTestContext context) { + // install - java + assertThat(context.getSoftwarePath().resolve("java/bin/java")).exists(); + + // commandlet - android-studio + if (context.getSystemInfo().isWindows()) { + assertThat(context.getSoftwarePath().resolve("android-studio/bin/studio")).doesNotExist(); + } else { + assertThat(context.getSoftwarePath().resolve("android-studio/bin/studio")).exists().isSymbolicLink(); + } + assertThat(context.getSoftwarePath().resolve("android-studio/.ide.software.version")).exists().hasContent("2024.1.1.1"); + assertLogMessage(context, IdeLogLevel.SUCCESS, "Successfully installed java in version 17.0.10_7"); + assertLogMessage(context, IdeLogLevel.SUCCESS, "Successfully installed android-studio in version 2024.1.1.1"); + } + +} diff --git a/cli/src/test/resources/ide-projects/android-studio/_ide/urls/readme b/cli/src/test/resources/ide-projects/android-studio/_ide/urls/readme new file mode 100644 index 000000000..befcdfa75 --- /dev/null +++ b/cli/src/test/resources/ide-projects/android-studio/_ide/urls/readme @@ -0,0 +1 @@ +this is the download metadata \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/android-studio/project/home/.ide/ide.properties b/cli/src/test/resources/ide-projects/android-studio/project/home/.ide/ide.properties new file mode 100644 index 000000000..e69de29bb diff --git a/cli/src/test/resources/ide-projects/android-studio/project/home/readme b/cli/src/test/resources/ide-projects/android-studio/project/home/readme new file mode 100644 index 000000000..5e8bc178c --- /dev/null +++ b/cli/src/test/resources/ide-projects/android-studio/project/home/readme @@ -0,0 +1 @@ +this is the users HOME directory \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/android-studio/project/readme b/cli/src/test/resources/ide-projects/android-studio/project/readme new file mode 100644 index 000000000..256f5732c --- /dev/null +++ b/cli/src/test/resources/ide-projects/android-studio/project/readme @@ -0,0 +1 @@ +this is the IDE_HOME directory \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/android-studio/project/settings/ide.properties b/cli/src/test/resources/ide-projects/android-studio/project/settings/ide.properties new file mode 100644 index 000000000..751d10729 --- /dev/null +++ b/cli/src/test/resources/ide-projects/android-studio/project/settings/ide.properties @@ -0,0 +1,2 @@ +JAVA_VERSION=17.0.10_7 +ANDROID-STUDIO_VERSION=2024.1.1.1 \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/android-studio/project/workspaces/main/readme b/cli/src/test/resources/ide-projects/android-studio/project/workspaces/main/readme new file mode 100644 index 000000000..f04b5be39 --- /dev/null +++ b/cli/src/test/resources/ide-projects/android-studio/project/workspaces/main/readme @@ -0,0 +1 @@ +this is the main workspace of jmc test case \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/android-studio/readme b/cli/src/test/resources/ide-projects/android-studio/readme new file mode 100644 index 000000000..15b91829e --- /dev/null +++ b/cli/src/test/resources/ide-projects/android-studio/readme @@ -0,0 +1 @@ +this is the IDE_ROOT directory \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/android-studio/repository/android-studio/android-studio/default/linux/bin/studio.sh b/cli/src/test/resources/ide-projects/android-studio/repository/android-studio/android-studio/default/linux/bin/studio.sh new file mode 100644 index 000000000..b07f8b63b --- /dev/null +++ b/cli/src/test/resources/ide-projects/android-studio/repository/android-studio/android-studio/default/linux/bin/studio.sh @@ -0,0 +1,2 @@ +#!/bin/bash +echo "android-studio linux $*" \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/android-studio/repository/android-studio/android-studio/default/mac/bin/studio.sh b/cli/src/test/resources/ide-projects/android-studio/repository/android-studio/android-studio/default/mac/bin/studio.sh new file mode 100644 index 000000000..6c0c7a6e1 --- /dev/null +++ b/cli/src/test/resources/ide-projects/android-studio/repository/android-studio/android-studio/default/mac/bin/studio.sh @@ -0,0 +1,2 @@ +#!/bin/bash +echo "android-studio mac $*" \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/android-studio/repository/java/java/default/bin/java b/cli/src/test/resources/ide-projects/android-studio/repository/java/java/default/bin/java new file mode 100644 index 000000000..0aa8af9dc --- /dev/null +++ b/cli/src/test/resources/ide-projects/android-studio/repository/java/java/default/bin/java @@ -0,0 +1,2 @@ +#!/bin/bash +echo "java $*" \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/android-studio/repository/java/java/default/bin/java.cmd b/cli/src/test/resources/ide-projects/android-studio/repository/java/java/default/bin/java.cmd new file mode 100644 index 000000000..669f13167 --- /dev/null +++ b/cli/src/test/resources/ide-projects/android-studio/repository/java/java/default/bin/java.cmd @@ -0,0 +1,2 @@ +@echo off +echo java % \ No newline at end of file From 46ce1f9447194d8956857f54fe265a5e1bd78ac8 Mon Sep 17 00:00:00 2001 From: jan-vcapgemini Date: Mon, 22 Apr 2024 20:21:31 +0200 Subject: [PATCH 06/20] #12: removed symlink creation added testAndroidStudioRun test removed postInstall added simulated studio64.exe --- .../ide/tool/androidstudio/AndroidStudio.java | 18 ++--------- .../tool/androidstudio/AndroidStudioTest.java | 30 +++++++++++++++---- .../default/windows/bin/studio64.exe | 2 ++ 3 files changed, 28 insertions(+), 22 deletions(-) create mode 100644 cli/src/test/resources/ide-projects/android-studio/repository/android-studio/android-studio/default/windows/bin/studio64.exe diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java b/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java index 17f6e0b4d..e3b0d673b 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java @@ -3,7 +3,6 @@ import com.devonfw.tools.ide.cli.CliArgument; import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.io.FileAccess; import com.devonfw.tools.ide.process.ProcessContext; import com.devonfw.tools.ide.process.ProcessErrorHandling; import com.devonfw.tools.ide.process.ProcessMode; @@ -80,10 +79,10 @@ protected ProcessResult runAndroidStudio(ProcessMode processMode, String... args toolPath = getToolBinPath().resolve(STUDIO64_EXE); } else { // check bin folder - toolPath = getToolBinPath().resolve(STUDIO); + toolPath = getToolBinPath().resolve(STUDIO_BASH); if (!Files.exists(toolPath)) { // check tool root folder - toolPath = getToolPath().resolve(STUDIO); + toolPath = getToolPath().resolve(STUDIO_BASH); } } ProcessContext pc = this.context.newProcess(); @@ -107,19 +106,6 @@ public boolean install(boolean silent) { return super.install(silent); } - @Override - protected void postInstall() { - - super.postInstall(); - Path scriptPath = getToolBinPath().resolve(STUDIO_BASH); - - // TODO: Check if this is still needed. - if (Files.exists(scriptPath)) { - FileAccess fileAccess = this.context.getFileAccess(); - fileAccess.symlink(scriptPath, getToolBinPath().resolve(STUDIO), true); - } - } - @Override public void installPlugin(PluginDescriptor plugin) { diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudioTest.java b/cli/src/test/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudioTest.java index 87653a26f..2ae625f73 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudioTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudioTest.java @@ -20,7 +20,6 @@ public void testAndroidStudioInstall(String os) { // arrange SystemInfo systemInfo = SystemInfoMock.of(os); context.setSystemInfo(systemInfo); - IdeTestContext context = newContext(PROJECT_ANDROID_STUDIO); AndroidStudio commandlet = new AndroidStudio(context); // act @@ -30,16 +29,35 @@ public void testAndroidStudioInstall(String os) { checkInstallation(context); } + @ParameterizedTest + @ValueSource(strings = { "windows", "mac", "linux" }) + public void testAndroidStudioRun(String os) { + // arrange + SystemInfo systemInfo = SystemInfoMock.of(os); + context.setSystemInfo(systemInfo); + AndroidStudio commandlet = new AndroidStudio(context); + + // act + commandlet.run(); + + // assert + if (context.getSystemInfo().isMac()) { + assertLogMessage(context, IdeLogLevel.INFO, "android-studio mac open -na " + context.getWorkspacePath()); + } + if (context.getSystemInfo().isLinux()) { + assertLogMessage(context, IdeLogLevel.INFO, "android-studio linux open -na " + context.getWorkspacePath()); + } + if (context.getSystemInfo().isWindows()) { + assertLogMessage(context, IdeLogLevel.INFO, "android-studio windows " + context.getWorkspacePath()); + } + checkInstallation(context); + } + private void checkInstallation(IdeTestContext context) { // install - java assertThat(context.getSoftwarePath().resolve("java/bin/java")).exists(); // commandlet - android-studio - if (context.getSystemInfo().isWindows()) { - assertThat(context.getSoftwarePath().resolve("android-studio/bin/studio")).doesNotExist(); - } else { - assertThat(context.getSoftwarePath().resolve("android-studio/bin/studio")).exists().isSymbolicLink(); - } assertThat(context.getSoftwarePath().resolve("android-studio/.ide.software.version")).exists().hasContent("2024.1.1.1"); assertLogMessage(context, IdeLogLevel.SUCCESS, "Successfully installed java in version 17.0.10_7"); assertLogMessage(context, IdeLogLevel.SUCCESS, "Successfully installed android-studio in version 2024.1.1.1"); diff --git a/cli/src/test/resources/ide-projects/android-studio/repository/android-studio/android-studio/default/windows/bin/studio64.exe b/cli/src/test/resources/ide-projects/android-studio/repository/android-studio/android-studio/default/windows/bin/studio64.exe new file mode 100644 index 000000000..d813ccb12 --- /dev/null +++ b/cli/src/test/resources/ide-projects/android-studio/repository/android-studio/android-studio/default/windows/bin/studio64.exe @@ -0,0 +1,2 @@ +#!/bin/bash +echo "android-studio windows $*" \ No newline at end of file From a32cb194e0eab430c6f7b9d9fe93623f3e3f5eae Mon Sep 17 00:00:00 2001 From: jan-vcapgemini Date: Tue, 23 Apr 2024 10:44:35 +0200 Subject: [PATCH 07/20] #12: cleanup removed unnecessary JDK installation (already included in SDK) removed unnecessary readme files and folders added javadocs added studio64.exe to .gitattributes to be handled as text file --- .gitattributes | 5 ++++- .../ide/tool/androidstudio/AndroidStudio.java | 2 -- .../tool/androidstudio/AndroidStudioTest.java | 17 +++++++++++++---- .../android-studio/_ide/urls/readme | 1 - .../project/home/.ide/ide.properties | 0 .../android-studio/project/home/readme | 1 - .../ide-projects/android-studio/project/readme | 1 - .../project/settings/ide.properties | 1 - .../project/workspaces/main/readme | 1 - .../ide-projects/android-studio/readme | 1 - .../repository/java/java/default/bin/java | 2 -- .../repository/java/java/default/bin/java.cmd | 2 -- 12 files changed, 17 insertions(+), 17 deletions(-) delete mode 100644 cli/src/test/resources/ide-projects/android-studio/_ide/urls/readme delete mode 100644 cli/src/test/resources/ide-projects/android-studio/project/home/.ide/ide.properties delete mode 100644 cli/src/test/resources/ide-projects/android-studio/project/home/readme delete mode 100644 cli/src/test/resources/ide-projects/android-studio/project/readme delete mode 100644 cli/src/test/resources/ide-projects/android-studio/readme delete mode 100644 cli/src/test/resources/ide-projects/android-studio/repository/java/java/default/bin/java delete mode 100644 cli/src/test/resources/ide-projects/android-studio/repository/java/java/default/bin/java.cmd diff --git a/.gitattributes b/.gitattributes index 931eb4a75..36ff00b2b 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,4 +5,7 @@ *.tgz binary *.tar binary *.bz2 binary -*.gz binary \ No newline at end of file +*.gz binary + +# special handling for test files +cli/src/test/resources/ide-projects/android-studio/repository/android-studio/android-studio/default/windows/bin/studio64.exe text \ No newline at end of file diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java b/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java index e3b0d673b..a5a2a20d1 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java @@ -10,7 +10,6 @@ import com.devonfw.tools.ide.step.Step; import com.devonfw.tools.ide.tool.ide.IdeToolCommandlet; import com.devonfw.tools.ide.tool.ide.PluginDescriptor; -import com.devonfw.tools.ide.tool.java.Java; import java.nio.file.Files; import java.nio.file.Path; @@ -102,7 +101,6 @@ protected ProcessResult runAndroidStudio(ProcessMode processMode, String... args @Override public boolean install(boolean silent) { - getCommandlet(Java.class).install(); return super.install(silent); } diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudioTest.java b/cli/src/test/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudioTest.java index 2ae625f73..9afc23412 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudioTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudioTest.java @@ -8,12 +8,20 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; +/** + * Test class for {@link AndroidStudio Android Studio IDE} tests. + */ public class AndroidStudioTest extends AbstractIdeContextTest { private static final String PROJECT_ANDROID_STUDIO = "android-studio"; private final IdeTestContext context = newContext(PROJECT_ANDROID_STUDIO); + /** + * Tests if {@link AndroidStudio Android Studio IDE} can be installed. + * + * @param os String of the OS to use. + */ @ParameterizedTest @ValueSource(strings = { "windows", "mac", "linux" }) public void testAndroidStudioInstall(String os) { @@ -29,6 +37,11 @@ public void testAndroidStudioInstall(String os) { checkInstallation(context); } + /** + * Tests if {@link AndroidStudio Android Studio IDE} can be run. + * + * @param os String of the OS to use. + */ @ParameterizedTest @ValueSource(strings = { "windows", "mac", "linux" }) public void testAndroidStudioRun(String os) { @@ -54,12 +67,8 @@ public void testAndroidStudioRun(String os) { } private void checkInstallation(IdeTestContext context) { - // install - java - assertThat(context.getSoftwarePath().resolve("java/bin/java")).exists(); - // commandlet - android-studio assertThat(context.getSoftwarePath().resolve("android-studio/.ide.software.version")).exists().hasContent("2024.1.1.1"); - assertLogMessage(context, IdeLogLevel.SUCCESS, "Successfully installed java in version 17.0.10_7"); assertLogMessage(context, IdeLogLevel.SUCCESS, "Successfully installed android-studio in version 2024.1.1.1"); } diff --git a/cli/src/test/resources/ide-projects/android-studio/_ide/urls/readme b/cli/src/test/resources/ide-projects/android-studio/_ide/urls/readme deleted file mode 100644 index befcdfa75..000000000 --- a/cli/src/test/resources/ide-projects/android-studio/_ide/urls/readme +++ /dev/null @@ -1 +0,0 @@ -this is the download metadata \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/android-studio/project/home/.ide/ide.properties b/cli/src/test/resources/ide-projects/android-studio/project/home/.ide/ide.properties deleted file mode 100644 index e69de29bb..000000000 diff --git a/cli/src/test/resources/ide-projects/android-studio/project/home/readme b/cli/src/test/resources/ide-projects/android-studio/project/home/readme deleted file mode 100644 index 5e8bc178c..000000000 --- a/cli/src/test/resources/ide-projects/android-studio/project/home/readme +++ /dev/null @@ -1 +0,0 @@ -this is the users HOME directory \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/android-studio/project/readme b/cli/src/test/resources/ide-projects/android-studio/project/readme deleted file mode 100644 index 256f5732c..000000000 --- a/cli/src/test/resources/ide-projects/android-studio/project/readme +++ /dev/null @@ -1 +0,0 @@ -this is the IDE_HOME directory \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/android-studio/project/settings/ide.properties b/cli/src/test/resources/ide-projects/android-studio/project/settings/ide.properties index 751d10729..4f82e8b41 100644 --- a/cli/src/test/resources/ide-projects/android-studio/project/settings/ide.properties +++ b/cli/src/test/resources/ide-projects/android-studio/project/settings/ide.properties @@ -1,2 +1 @@ -JAVA_VERSION=17.0.10_7 ANDROID-STUDIO_VERSION=2024.1.1.1 \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/android-studio/project/workspaces/main/readme b/cli/src/test/resources/ide-projects/android-studio/project/workspaces/main/readme index f04b5be39..e69de29bb 100644 --- a/cli/src/test/resources/ide-projects/android-studio/project/workspaces/main/readme +++ b/cli/src/test/resources/ide-projects/android-studio/project/workspaces/main/readme @@ -1 +0,0 @@ -this is the main workspace of jmc test case \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/android-studio/readme b/cli/src/test/resources/ide-projects/android-studio/readme deleted file mode 100644 index 15b91829e..000000000 --- a/cli/src/test/resources/ide-projects/android-studio/readme +++ /dev/null @@ -1 +0,0 @@ -this is the IDE_ROOT directory \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/android-studio/repository/java/java/default/bin/java b/cli/src/test/resources/ide-projects/android-studio/repository/java/java/default/bin/java deleted file mode 100644 index 0aa8af9dc..000000000 --- a/cli/src/test/resources/ide-projects/android-studio/repository/java/java/default/bin/java +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -echo "java $*" \ No newline at end of file diff --git a/cli/src/test/resources/ide-projects/android-studio/repository/java/java/default/bin/java.cmd b/cli/src/test/resources/ide-projects/android-studio/repository/java/java/default/bin/java.cmd deleted file mode 100644 index 669f13167..000000000 --- a/cli/src/test/resources/ide-projects/android-studio/repository/java/java/default/bin/java.cmd +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -echo java % \ No newline at end of file From 4acb2e784129a119c7d1198f76656dabb57f95c1 Mon Sep 17 00:00:00 2001 From: jan-vcapgemini Date: Tue, 23 Apr 2024 21:59:12 +0200 Subject: [PATCH 08/20] #12: added proper MacOS implementation added test resources for MacOS run test added old bash script creation (WIP probably not needed at all) --- .../ide/tool/androidstudio/AndroidStudio.java | 63 ++++++++++++++++--- .../Contents/MacOS/studio} | 0 2 files changed, 56 insertions(+), 7 deletions(-) rename cli/src/test/resources/ide-projects/android-studio/repository/android-studio/android-studio/default/mac/{bin/studio.sh => Android Studio Preview.app/Contents/MacOS/studio} (100%) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java b/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java index a5a2a20d1..fceadf278 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java @@ -3,6 +3,7 @@ import com.devonfw.tools.ide.cli.CliArgument; import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.io.FileAccessImpl; import com.devonfw.tools.ide.process.ProcessContext; import com.devonfw.tools.ide.process.ProcessErrorHandling; import com.devonfw.tools.ide.process.ProcessMode; @@ -11,8 +12,11 @@ import com.devonfw.tools.ide.tool.ide.IdeToolCommandlet; import com.devonfw.tools.ide.tool.ide.PluginDescriptor; +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.PosixFilePermissions; import java.util.Set; /** @@ -72,20 +76,25 @@ protected void runIde(String... args) { */ protected ProcessResult runAndroidStudio(ProcessMode processMode, String... args) { - Path toolPath; + Path toolPath = null; // TODO: Check if this can be optimized. if (this.context.getSystemInfo().isWindows()) { toolPath = getToolBinPath().resolve(STUDIO64_EXE); - } else { - // check bin folder + } + + if (this.context.getSystemInfo().isLinux()) { toolPath = getToolBinPath().resolve(STUDIO_BASH); - if (!Files.exists(toolPath)) { - // check tool root folder - toolPath = getToolPath().resolve(STUDIO_BASH); - } } + + if (this.context.getSystemInfo().isMac()) { + // if (Files.exists(getToolBinPath().resolve(STUDIO))) { + toolPath = getToolPath().resolve("Studio.app").resolve("Contents").resolve("MacOS").resolve("studio"); + // } + } + ProcessContext pc = this.context.newProcess(); + assert toolPath != null; if (Files.exists(toolPath)) { pc.executable(toolPath); } @@ -104,6 +113,46 @@ public boolean install(boolean silent) { return super.install(silent); } + @Override + protected void postInstall() { + + super.postInstall(); + if (this.context.getSystemInfo().isMac()) { + if (getEdition().equals("ultimate")) { + + } else { + this.context.getFileAccess().move(getToolPath().resolve("Android Studio Preview.app"), getToolPath().resolve("Studio.app")); + // this.context.getFileAccess().mkdirs(getToolPath().resolve("bin")); + // Path binaryFile; + // try { + // binaryFile = Files.createFile(getToolBinPath().resolve("studio")); + // Files.writeString(binaryFile, + // "#!/usr/bin/env bash\n'" + getToolPath().resolve("Studio.app").resolve("Contents").resolve("MacOS").resolve("studio") + "' \\$@"); + // } catch (IOException e) { + // throw new RuntimeException(e); + // } + // // Setting execute permissions is only required if executed on a real MacOS, won't work on Windows. + // if (SystemInfoImpl.INSTANCE.isMac()) { + // setMacOsFilePermissions(binaryFile); + // } + + } + } + } + + private static void setMacOsFilePermissions(Path binaryFile) { + + if (Files.exists(binaryFile)) { + String permissionStr = FileAccessImpl.generatePermissionString(111); + Set permissions = PosixFilePermissions.fromString(permissionStr); + try { + Files.setPosixFilePermissions(binaryFile, permissions); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + @Override public void installPlugin(PluginDescriptor plugin) { diff --git a/cli/src/test/resources/ide-projects/android-studio/repository/android-studio/android-studio/default/mac/bin/studio.sh b/cli/src/test/resources/ide-projects/android-studio/repository/android-studio/android-studio/default/mac/Android Studio Preview.app/Contents/MacOS/studio similarity index 100% rename from cli/src/test/resources/ide-projects/android-studio/repository/android-studio/android-studio/default/mac/bin/studio.sh rename to cli/src/test/resources/ide-projects/android-studio/repository/android-studio/android-studio/default/mac/Android Studio Preview.app/Contents/MacOS/studio From c4f32a36bdc8c03c6f4b2ef014000109570ef1f0 Mon Sep 17 00:00:00 2001 From: jan-vcapgemini Date: Wed, 24 Apr 2024 16:07:58 +0200 Subject: [PATCH 09/20] #12: fixed extractDmg changed FileCopyMode from default to overwrite tree --- cli/src/main/java/com/devonfw/tools/ide/io/FileAccessImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/io/FileAccessImpl.java b/cli/src/main/java/com/devonfw/tools/ide/io/FileAccessImpl.java index 15dbbc3e2..0376400eb 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/io/FileAccessImpl.java +++ b/cli/src/main/java/com/devonfw/tools/ide/io/FileAccessImpl.java @@ -652,7 +652,7 @@ public void extractDmg(Path file, Path targetDir) { if (appPath == null) { throw new IllegalStateException("Failed to unpack DMG as no MacOS *.app was found in file " + file); } - copy(appPath, targetDir); + copy(appPath, targetDir, FileCopyMode.COPY_TREE_OVERRIDE_TREE); pc.addArgs("detach", "-force", mountPath); pc.run(); } From e135fda3c74da53171d5f3cff7848e7900e499c2 Mon Sep 17 00:00:00 2001 From: jan-vcapgemini Date: Wed, 24 Apr 2024 16:09:25 +0200 Subject: [PATCH 10/20] #12: cleanup and fix open replaced faulty tool path with open command for MacOS removed postInstall method --- .../ide/tool/androidstudio/AndroidStudio.java | 51 ++++--------------- 1 file changed, 10 insertions(+), 41 deletions(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java b/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java index fceadf278..fb2b2ce05 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java @@ -48,11 +48,14 @@ protected void runIde(String... args) { Step stepRun = this.context.newStep("Running Android Studio"); try { ProcessResult result; - if (this.context.getSystemInfo().isWindows()) { - result = runAndroidStudio(ProcessMode.BACKGROUND, CliArgument.prepend(args, this.context.getWorkspacePath().toString())); + if (this.context.getSystemInfo().isMac()) { + result = runAndroidStudio(ProcessMode.BACKGROUND, + CliArgument.prepend(args, getToolPath().resolve("Contents").resolve("MacOS").resolve("studio").toString(), + this.context.getWorkspacePath().toString())); } else { - result = runAndroidStudio(ProcessMode.BACKGROUND, CliArgument.prepend(args, "open", "-na", this.context.getWorkspacePath().toString())); + result = runAndroidStudio(ProcessMode.BACKGROUND, CliArgument.prepend(args, this.context.getWorkspacePath().toString())); } + if (result.isSuccessful()) { stepRun.success("Running Android Studio successfully."); } else { @@ -76,25 +79,18 @@ protected void runIde(String... args) { */ protected ProcessResult runAndroidStudio(ProcessMode processMode, String... args) { - Path toolPath = null; + Path toolPath; // TODO: Check if this can be optimized. if (this.context.getSystemInfo().isWindows()) { toolPath = getToolBinPath().resolve(STUDIO64_EXE); - } - - if (this.context.getSystemInfo().isLinux()) { + } else if (this.context.getSystemInfo().isLinux()) { toolPath = getToolBinPath().resolve(STUDIO_BASH); - } - - if (this.context.getSystemInfo().isMac()) { - // if (Files.exists(getToolBinPath().resolve(STUDIO))) { - toolPath = getToolPath().resolve("Studio.app").resolve("Contents").resolve("MacOS").resolve("studio"); - // } + } else { + toolPath = Path.of("open"); } ProcessContext pc = this.context.newProcess(); - assert toolPath != null; if (Files.exists(toolPath)) { pc.executable(toolPath); } @@ -113,33 +109,6 @@ public boolean install(boolean silent) { return super.install(silent); } - @Override - protected void postInstall() { - - super.postInstall(); - if (this.context.getSystemInfo().isMac()) { - if (getEdition().equals("ultimate")) { - - } else { - this.context.getFileAccess().move(getToolPath().resolve("Android Studio Preview.app"), getToolPath().resolve("Studio.app")); - // this.context.getFileAccess().mkdirs(getToolPath().resolve("bin")); - // Path binaryFile; - // try { - // binaryFile = Files.createFile(getToolBinPath().resolve("studio")); - // Files.writeString(binaryFile, - // "#!/usr/bin/env bash\n'" + getToolPath().resolve("Studio.app").resolve("Contents").resolve("MacOS").resolve("studio") + "' \\$@"); - // } catch (IOException e) { - // throw new RuntimeException(e); - // } - // // Setting execute permissions is only required if executed on a real MacOS, won't work on Windows. - // if (SystemInfoImpl.INSTANCE.isMac()) { - // setMacOsFilePermissions(binaryFile); - // } - - } - } - } - private static void setMacOsFilePermissions(Path binaryFile) { if (Files.exists(binaryFile)) { From 0b482212f50cea3cafe61bcec2a33ad7b77d6b6a Mon Sep 17 00:00:00 2001 From: jan-vcapgemini Date: Thu, 25 Apr 2024 18:10:55 +0200 Subject: [PATCH 11/20] #12: cleanup and fixes --- .../ide/tool/androidstudio/AndroidStudio.java | 26 ++------------- .../tool/androidstudio/AndroidStudioTest.java | 33 ++++++++++--------- .../Contents/MacOS/studio => bin/open} | 0 3 files changed, 20 insertions(+), 39 deletions(-) rename cli/src/test/resources/ide-projects/android-studio/repository/android-studio/android-studio/default/mac/{Android Studio Preview.app/Contents/MacOS/studio => bin/open} (100%) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java b/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java index fb2b2ce05..80e1a0a3d 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java @@ -3,7 +3,6 @@ import com.devonfw.tools.ide.cli.CliArgument; import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.io.FileAccessImpl; import com.devonfw.tools.ide.process.ProcessContext; import com.devonfw.tools.ide.process.ProcessErrorHandling; import com.devonfw.tools.ide.process.ProcessMode; @@ -12,11 +11,7 @@ import com.devonfw.tools.ide.tool.ide.IdeToolCommandlet; import com.devonfw.tools.ide.tool.ide.PluginDescriptor; -import java.io.IOException; -import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.attribute.PosixFilePermission; -import java.nio.file.attribute.PosixFilePermissions; import java.util.Set; /** @@ -49,9 +44,9 @@ protected void runIde(String... args) { try { ProcessResult result; if (this.context.getSystemInfo().isMac()) { + Path studioPath = getToolPath().resolve("Contents").resolve("MacOS").resolve(STUDIO); result = runAndroidStudio(ProcessMode.BACKGROUND, - CliArgument.prepend(args, getToolPath().resolve("Contents").resolve("MacOS").resolve("studio").toString(), - this.context.getWorkspacePath().toString())); + CliArgument.prepend(args, "-na", studioPath.toString(), "--args", this.context.getWorkspacePath().toString())); } else { result = runAndroidStudio(ProcessMode.BACKGROUND, CliArgument.prepend(args, this.context.getWorkspacePath().toString())); } @@ -91,9 +86,7 @@ protected ProcessResult runAndroidStudio(ProcessMode processMode, String... args ProcessContext pc = this.context.newProcess(); - if (Files.exists(toolPath)) { - pc.executable(toolPath); - } + pc.executable(toolPath); if (processMode == ProcessMode.DEFAULT_CAPTURE) { pc.errorHandling(ProcessErrorHandling.ERROR); @@ -109,19 +102,6 @@ public boolean install(boolean silent) { return super.install(silent); } - private static void setMacOsFilePermissions(Path binaryFile) { - - if (Files.exists(binaryFile)) { - String permissionStr = FileAccessImpl.generatePermissionString(111); - Set permissions = PosixFilePermissions.fromString(permissionStr); - try { - Files.setPosixFilePermissions(binaryFile, permissions); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - } - @Override public void installPlugin(PluginDescriptor plugin) { diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudioTest.java b/cli/src/test/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudioTest.java index 9afc23412..cc08d1971 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudioTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudioTest.java @@ -13,9 +13,9 @@ */ public class AndroidStudioTest extends AbstractIdeContextTest { - private static final String PROJECT_ANDROID_STUDIO = "android-studio"; + private static final String ANDROID_STUDIO = "android-studio"; - private final IdeTestContext context = newContext(PROJECT_ANDROID_STUDIO); + private final IdeTestContext context = newContext(ANDROID_STUDIO); /** * Tests if {@link AndroidStudio Android Studio IDE} can be installed. @@ -27,14 +27,14 @@ public class AndroidStudioTest extends AbstractIdeContextTest { public void testAndroidStudioInstall(String os) { // arrange SystemInfo systemInfo = SystemInfoMock.of(os); - context.setSystemInfo(systemInfo); - AndroidStudio commandlet = new AndroidStudio(context); + this.context.setSystemInfo(systemInfo); + AndroidStudio commandlet = new AndroidStudio(this.context); // act commandlet.install(); // assert - checkInstallation(context); + checkInstallation(this.context); } /** @@ -47,23 +47,24 @@ public void testAndroidStudioInstall(String os) { public void testAndroidStudioRun(String os) { // arrange SystemInfo systemInfo = SystemInfoMock.of(os); - context.setSystemInfo(systemInfo); - AndroidStudio commandlet = new AndroidStudio(context); + this.context.setSystemInfo(systemInfo); + AndroidStudio commandlet = new AndroidStudio(this.context); // act commandlet.run(); // assert - if (context.getSystemInfo().isMac()) { - assertLogMessage(context, IdeLogLevel.INFO, "android-studio mac open -na " + context.getWorkspacePath()); + if (this.context.getSystemInfo().isMac()) { + assertLogMessage(this.context, IdeLogLevel.INFO, + ANDROID_STUDIO + " mac -na " + commandlet.getToolPath().resolve("Contents/MacOS/studio") + " --args " + this.context.getWorkspacePath()); + } else if (this.context.getSystemInfo().isLinux()) { + assertLogMessage(this.context, IdeLogLevel.INFO, ANDROID_STUDIO + " linux " + this.context.getWorkspacePath()); + } else if (this.context.getSystemInfo().isWindows()) { + assertLogMessage(this.context, IdeLogLevel.INFO, ANDROID_STUDIO + " windows " + this.context.getWorkspacePath()); } - if (context.getSystemInfo().isLinux()) { - assertLogMessage(context, IdeLogLevel.INFO, "android-studio linux open -na " + context.getWorkspacePath()); - } - if (context.getSystemInfo().isWindows()) { - assertLogMessage(context, IdeLogLevel.INFO, "android-studio windows " + context.getWorkspacePath()); - } - checkInstallation(context); + + assertLogMessage(this.context, IdeLogLevel.SUCCESS, "Running Android Studio successfully."); + checkInstallation(this.context); } private void checkInstallation(IdeTestContext context) { diff --git a/cli/src/test/resources/ide-projects/android-studio/repository/android-studio/android-studio/default/mac/Android Studio Preview.app/Contents/MacOS/studio b/cli/src/test/resources/ide-projects/android-studio/repository/android-studio/android-studio/default/mac/bin/open similarity index 100% rename from cli/src/test/resources/ide-projects/android-studio/repository/android-studio/android-studio/default/mac/Android Studio Preview.app/Contents/MacOS/studio rename to cli/src/test/resources/ide-projects/android-studio/repository/android-studio/android-studio/default/mac/bin/open From 8d26469077076181e2946565a8f37604ea4f791e Mon Sep 17 00:00:00 2001 From: jan-vcapgemini Date: Mon, 29 Apr 2024 14:38:03 +0200 Subject: [PATCH 12/20] #12: implemented requested change changed runAndroidStudio method to private --- .../devonfw/tools/ide/tool/androidstudio/AndroidStudio.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java b/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java index 80e1a0a3d..8f35c3847 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java @@ -66,16 +66,15 @@ protected void runIde(String... args) { } /** - * Runs AndroidStudio application. + * Runs the Android Studio application. * * @param processMode - the {@link ProcessMode}. * @param args the individual arguments to pass to Android Studio. * @return the {@link ProcessResult}. */ - protected ProcessResult runAndroidStudio(ProcessMode processMode, String... args) { + private ProcessResult runAndroidStudio(ProcessMode processMode, String... args) { Path toolPath; - // TODO: Check if this can be optimized. if (this.context.getSystemInfo().isWindows()) { toolPath = getToolBinPath().resolve(STUDIO64_EXE); } else if (this.context.getSystemInfo().isLinux()) { From 2efa4986508596e9d08ad433c18391998f38a492 Mon Sep 17 00:00:00 2001 From: jan-vcapgemini Date: Tue, 30 Apr 2024 15:40:33 +0200 Subject: [PATCH 13/20] #12: applied optimizations replaced runIde with runTool removed runAndroidStudio method adjusted test --- .../ide/tool/androidstudio/AndroidStudio.java | 66 ++++--------------- .../tool/androidstudio/AndroidStudioTest.java | 3 +- 2 files changed, 15 insertions(+), 54 deletions(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java b/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java index 8f35c3847..0f28be6d4 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java @@ -3,13 +3,10 @@ import com.devonfw.tools.ide.cli.CliArgument; import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.process.ProcessContext; -import com.devonfw.tools.ide.process.ProcessErrorHandling; import com.devonfw.tools.ide.process.ProcessMode; -import com.devonfw.tools.ide.process.ProcessResult; -import com.devonfw.tools.ide.step.Step; import com.devonfw.tools.ide.tool.ide.IdeToolCommandlet; import com.devonfw.tools.ide.tool.ide.PluginDescriptor; +import com.devonfw.tools.ide.version.VersionIdentifier; import java.nio.file.Path; import java.util.Set; @@ -36,63 +33,28 @@ public AndroidStudio(IdeContext context) { } @Override - protected void runIde(String... args) { - - install(true); - - Step stepRun = this.context.newStep("Running Android Studio"); - try { - ProcessResult result; - if (this.context.getSystemInfo().isMac()) { - Path studioPath = getToolPath().resolve("Contents").resolve("MacOS").resolve(STUDIO); - result = runAndroidStudio(ProcessMode.BACKGROUND, - CliArgument.prepend(args, "-na", studioPath.toString(), "--args", this.context.getWorkspacePath().toString())); - } else { - result = runAndroidStudio(ProcessMode.BACKGROUND, CliArgument.prepend(args, this.context.getWorkspacePath().toString())); - } - - if (result.isSuccessful()) { - stepRun.success("Running Android Studio successfully."); - } else { - stepRun.isFailure(); - } - - } catch (Exception e) { - stepRun.error(e, "Failed to run Android Studio."); - } finally { - stepRun.end(); - } - - } + protected String getBinaryName() { - /** - * Runs the Android Studio application. - * - * @param processMode - the {@link ProcessMode}. - * @param args the individual arguments to pass to Android Studio. - * @return the {@link ProcessResult}. - */ - private ProcessResult runAndroidStudio(ProcessMode processMode, String... args) { - - Path toolPath; if (this.context.getSystemInfo().isWindows()) { - toolPath = getToolBinPath().resolve(STUDIO64_EXE); + return STUDIO64_EXE; } else if (this.context.getSystemInfo().isLinux()) { - toolPath = getToolBinPath().resolve(STUDIO_BASH); + return STUDIO_BASH; } else { - toolPath = Path.of("open"); + return "open"; } + } - ProcessContext pc = this.context.newProcess(); - - pc.executable(toolPath); + @Override + public void runTool(ProcessMode processMode, VersionIdentifier toolVersion, String... args) { - if (processMode == ProcessMode.DEFAULT_CAPTURE) { - pc.errorHandling(ProcessErrorHandling.ERROR); + if (this.context.getSystemInfo().isMac()) { + Path studioPath = getToolPath().resolve("Contents").resolve("MacOS").resolve(STUDIO); + args = CliArgument.prepend(args, "-na", studioPath.toString(), "--args", this.context.getWorkspacePath().toString()); + } else { + args = CliArgument.prepend(args, this.context.getWorkspacePath().toString()); } - pc.addArgs(args); + super.runTool(processMode, toolVersion, args); - return pc.run(processMode); } @Override diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudioTest.java b/cli/src/test/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudioTest.java index cc08d1971..4e749c24f 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudioTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudioTest.java @@ -62,8 +62,7 @@ public void testAndroidStudioRun(String os) { } else if (this.context.getSystemInfo().isWindows()) { assertLogMessage(this.context, IdeLogLevel.INFO, ANDROID_STUDIO + " windows " + this.context.getWorkspacePath()); } - - assertLogMessage(this.context, IdeLogLevel.SUCCESS, "Running Android Studio successfully."); + checkInstallation(this.context); } From 170c8347f3059c84e36699098268caa2da363796 Mon Sep 17 00:00:00 2001 From: jan-vcapgemini Date: Fri, 3 May 2024 12:30:35 +0200 Subject: [PATCH 14/20] #12: re-added file permission setter --- .../ide/tool/androidstudio/AndroidStudio.java | 41 +++++++++++++++---- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java b/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java index 0f28be6d4..52048f99b 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java @@ -3,12 +3,17 @@ import com.devonfw.tools.ide.cli.CliArgument; import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.io.FileAccessImpl; import com.devonfw.tools.ide.process.ProcessMode; import com.devonfw.tools.ide.tool.ide.IdeToolCommandlet; import com.devonfw.tools.ide.tool.ide.PluginDescriptor; import com.devonfw.tools.ide.version.VersionIdentifier; +import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.PosixFilePermissions; import java.util.Set; /** @@ -36,23 +41,19 @@ public AndroidStudio(IdeContext context) { protected String getBinaryName() { if (this.context.getSystemInfo().isWindows()) { - return STUDIO64_EXE; + return getToolBinPath().resolve(STUDIO64_EXE).toString(); } else if (this.context.getSystemInfo().isLinux()) { - return STUDIO_BASH; + return getToolBinPath().resolve(STUDIO_BASH).toString(); } else { - return "open"; + return getToolPath().resolve("Android Studio Preview.app").resolve("Contents").resolve("MacOS").resolve(STUDIO).toString(); } } @Override public void runTool(ProcessMode processMode, VersionIdentifier toolVersion, String... args) { - if (this.context.getSystemInfo().isMac()) { - Path studioPath = getToolPath().resolve("Contents").resolve("MacOS").resolve(STUDIO); - args = CliArgument.prepend(args, "-na", studioPath.toString(), "--args", this.context.getWorkspacePath().toString()); - } else { - args = CliArgument.prepend(args, this.context.getWorkspacePath().toString()); - } + args = CliArgument.prepend(args, this.context.getWorkspacePath().toString()); + super.runTool(processMode, toolVersion, args); } @@ -63,6 +64,28 @@ public boolean install(boolean silent) { return super.install(silent); } + @Override + protected void postInstall() { + + super.postInstall(); + if (this.context.getSystemInfo().isMac()) { + setMacOsFilePermissions(getToolPath().resolve("Android Studio Preview.app").resolve("Contents").resolve("MacOS").resolve(STUDIO)); + } + } + + private static void setMacOsFilePermissions(Path binaryFile) { + + if (Files.exists(binaryFile)) { + String permissionStr = FileAccessImpl.generatePermissionString(493); + Set permissions = PosixFilePermissions.fromString(permissionStr); + try { + Files.setPosixFilePermissions(binaryFile, permissions); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + @Override public void installPlugin(PluginDescriptor plugin) { From aae698dfb4750f9fb680cbed7569dfbb260982a9 Mon Sep 17 00:00:00 2001 From: jan-vcapgemini Date: Fri, 3 May 2024 14:16:51 +0200 Subject: [PATCH 15/20] #12: fixed tests --- .../ide/tool/androidstudio/AndroidStudio.java | 19 ++++++++++++------- .../tool/androidstudio/AndroidStudioTest.java | 5 ++--- .../Contents/MacOS/studio} | 0 3 files changed, 14 insertions(+), 10 deletions(-) rename cli/src/test/resources/ide-projects/android-studio/repository/android-studio/android-studio/default/mac/{bin/open => Android Studio Preview.app/Contents/MacOS/studio} (100%) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java b/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java index 52048f99b..9484adf79 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java @@ -4,6 +4,7 @@ import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.context.IdeContext; import com.devonfw.tools.ide.io.FileAccessImpl; +import com.devonfw.tools.ide.os.SystemInfoImpl; import com.devonfw.tools.ide.process.ProcessMode; import com.devonfw.tools.ide.tool.ide.IdeToolCommandlet; import com.devonfw.tools.ide.tool.ide.PluginDescriptor; @@ -54,6 +55,7 @@ public void runTool(ProcessMode processMode, VersionIdentifier toolVersion, Stri args = CliArgument.prepend(args, this.context.getWorkspacePath().toString()); + install(true); super.runTool(processMode, toolVersion, args); } @@ -75,15 +77,18 @@ protected void postInstall() { private static void setMacOsFilePermissions(Path binaryFile) { - if (Files.exists(binaryFile)) { - String permissionStr = FileAccessImpl.generatePermissionString(493); - Set permissions = PosixFilePermissions.fromString(permissionStr); - try { - Files.setPosixFilePermissions(binaryFile, permissions); - } catch (IOException e) { - throw new RuntimeException(e); + if (SystemInfoImpl.INSTANCE.isMac()) { + if (Files.exists(binaryFile)) { + String permissionStr = FileAccessImpl.generatePermissionString(493); + Set permissions = PosixFilePermissions.fromString(permissionStr); + try { + Files.setPosixFilePermissions(binaryFile, permissions); + } catch (IOException e) { + throw new RuntimeException(e); + } } } + } @Override diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudioTest.java b/cli/src/test/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudioTest.java index 4e749c24f..36d781d80 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudioTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudioTest.java @@ -55,14 +55,13 @@ public void testAndroidStudioRun(String os) { // assert if (this.context.getSystemInfo().isMac()) { - assertLogMessage(this.context, IdeLogLevel.INFO, - ANDROID_STUDIO + " mac -na " + commandlet.getToolPath().resolve("Contents/MacOS/studio") + " --args " + this.context.getWorkspacePath()); + assertLogMessage(this.context, IdeLogLevel.INFO, ANDROID_STUDIO + " mac " + this.context.getWorkspacePath()); } else if (this.context.getSystemInfo().isLinux()) { assertLogMessage(this.context, IdeLogLevel.INFO, ANDROID_STUDIO + " linux " + this.context.getWorkspacePath()); } else if (this.context.getSystemInfo().isWindows()) { assertLogMessage(this.context, IdeLogLevel.INFO, ANDROID_STUDIO + " windows " + this.context.getWorkspacePath()); } - + checkInstallation(this.context); } diff --git a/cli/src/test/resources/ide-projects/android-studio/repository/android-studio/android-studio/default/mac/bin/open b/cli/src/test/resources/ide-projects/android-studio/repository/android-studio/android-studio/default/mac/Android Studio Preview.app/Contents/MacOS/studio similarity index 100% rename from cli/src/test/resources/ide-projects/android-studio/repository/android-studio/android-studio/default/mac/bin/open rename to cli/src/test/resources/ide-projects/android-studio/repository/android-studio/android-studio/default/mac/Android Studio Preview.app/Contents/MacOS/studio From b6396e361bc595fa9c69719e0e32b50650c8d3c3 Mon Sep 17 00:00:00 2001 From: jan-vcapgemini Date: Thu, 30 May 2024 11:25:45 +0200 Subject: [PATCH 16/20] #12: added documentation file --- documentation/android-studio.adoc | 52 +++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 documentation/android-studio.adoc diff --git a/documentation/android-studio.adoc b/documentation/android-studio.adoc new file mode 100644 index 000000000..25f4f366a --- /dev/null +++ b/documentation/android-studio.adoc @@ -0,0 +1,52 @@ +:toc: +toc::[] + += android-studio + +The `android-studio` commandlet allows to install, configure, and launch https://developer.android.com/studio/[Android Studio]. +To launch Android Studio for your current workspace and `IDEasy` installation, simply run: +`ide android-studio` + +There are link:variables.asciidoc[variables] that can be used for Android Studio. +These are explained by the following table: + +.Variables of IDEasy for Android Studio +[options="header"] +|======================= +|*Variable*|*Meaning* +|*`ANDROID_STUDIO_VERSION`* |The version of the tool Android Studio to install and use. +|*`EXTRA_JAVA_VERSION`* |You can set this to a different (newer) version of Java used to launch your IDE (other than `JAVA_VERSION` that is used to build your project) +|======================= + +== plugins + +To be productive with Android Studio you need plugins. +Of course `IDEasy` can automate this for you: +In your link:settings.asciidoc[settings] git repository create a folder https://github.com/devonfw/ide-settings/tree/master/android-studio/plugins[android-studio/plugins] (click this link to see more examples and see which plugins come by default). +Here you can create a properties file for each plugin. +This is an example https://github.com/devonfw/ide-settings/blob/master/android-studio/plugins/asciidoc.properties[scala.properties]: +``` +plugin_id=org.asciidoctor.intellij.asciidoc +plugin_active=false +``` + +The variables are defined as following: + +* `plugin_id` defines the unique ID of the plugin to install. +If you want to customize `IDEasy` with new plugins use the search on https://plugins.jetbrains.com/androidstudio to find the plugin of your choice. +Select the tab `Versions` and click on a version in the list. +The plugin ID is displayed in the upper right corner. +Copy & paste the ID from here to make up your own custom config. +* `plugin_active` is an optional parameter. +If it is `true` (default) the plugin will be installed automatically during the project link:setup.asciidoc[setup] for all developers in your team. +Otherwise, developers can still install the plugin manually via `ide android-studio add-plugin «plugin_id»`. + +In general, you should try to stick with the configuration pre-defined by your project. +But some plugins may be considered as personal flavor and are typically not predefined by the project config. +Such plugins should be shipped with your link:settings.asciidoc[settings] as described above with `plugin_active=false` allowing you to easily install it manually. +Surely, you can easily add plugins via the UI of Android Studio. +However, be aware that some plugins may collect sensitive data or could introduce other vulnerabilities. +So consider the governance of your project and talk to your technical lead before installing additional plugins that are not pre-defined in your link:settings.asciidoc[settings]. + +As maintainer of the link:settings.asciidoc[settings] for your project you should avoid to ship too many plugins that may waste resources but are not used by every developer. +By configuring additional plugins with `plugin_active=false` you can give your developers the freedom to install some additional plugins easily. From ef61d5d07d6950084b9aa03bf627c6733bbcd3a4 Mon Sep 17 00:00:00 2001 From: jan-vcapgemini Date: Fri, 5 Jul 2024 17:12:15 +0200 Subject: [PATCH 17/20] #12: applied changes from intellij --- .../ide/tool/androidstudio/AndroidStudio.java | 32 ++++++++----------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java b/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java index 9484adf79..fe696d176 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java +++ b/cli/src/main/java/com/devonfw/tools/ide/tool/androidstudio/AndroidStudio.java @@ -3,8 +3,7 @@ import com.devonfw.tools.ide.cli.CliArgument; import com.devonfw.tools.ide.common.Tag; import com.devonfw.tools.ide.context.IdeContext; -import com.devonfw.tools.ide.io.FileAccessImpl; -import com.devonfw.tools.ide.os.SystemInfoImpl; +import com.devonfw.tools.ide.io.FileAccess; import com.devonfw.tools.ide.process.ProcessMode; import com.devonfw.tools.ide.tool.ide.IdeToolCommandlet; import com.devonfw.tools.ide.tool.ide.PluginDescriptor; @@ -13,8 +12,6 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.attribute.PosixFilePermission; -import java.nio.file.attribute.PosixFilePermissions; import java.util.Set; /** @@ -41,12 +38,13 @@ public AndroidStudio(IdeContext context) { @Override protected String getBinaryName() { + Path toolBinPath = getToolBinPath(); if (this.context.getSystemInfo().isWindows()) { - return getToolBinPath().resolve(STUDIO64_EXE).toString(); + return STUDIO64_EXE; } else if (this.context.getSystemInfo().isLinux()) { - return getToolBinPath().resolve(STUDIO_BASH).toString(); + return STUDIO_BASH; } else { - return getToolPath().resolve("Android Studio Preview.app").resolve("Contents").resolve("MacOS").resolve(STUDIO).toString(); + return STUDIO; } } @@ -75,20 +73,16 @@ protected void postInstall() { } } - private static void setMacOsFilePermissions(Path binaryFile) { - - if (SystemInfoImpl.INSTANCE.isMac()) { - if (Files.exists(binaryFile)) { - String permissionStr = FileAccessImpl.generatePermissionString(493); - Set permissions = PosixFilePermissions.fromString(permissionStr); - try { - Files.setPosixFilePermissions(binaryFile, permissions); - } catch (IOException e) { - throw new RuntimeException(e); - } + private void setMacOsFilePermissions(Path binaryFile) { + + if (Files.exists(binaryFile)) { + FileAccess fileAccess = this.context.getFileAccess(); + try { + fileAccess.makeExecutable(binaryFile); + } catch (IOException e) { + throw new RuntimeException(e); } } - } @Override From f387f3b4c400f5965504c41ddf4361dc7af24abc Mon Sep 17 00:00:00 2001 From: jan-vcapgemini Date: Fri, 5 Jul 2024 18:15:54 +0200 Subject: [PATCH 18/20] #12: added detailed help --- cli/src/main/resources/nls/Help.properties | 1 + cli/src/main/resources/nls/Help_de.properties | 1 + 2 files changed, 2 insertions(+) diff --git a/cli/src/main/resources/nls/Help.properties b/cli/src/main/resources/nls/Help.properties index a1c3aab65..d7fccaea2 100644 --- a/cli/src/main/resources/nls/Help.properties +++ b/cli/src/main/resources/nls/Help.properties @@ -1,6 +1,7 @@ cmd.--version=Print the version of IDEasy. cmd.--version.detail=TODO --version cmd.android-studio=Tool commandlet for Android Studio (IDE). +cmd.android-studio.detail=The android-studio commandlet allows to install, configure, and launch Android Studio. To launch Android Studio for your current workspace and IDEasy installation, simply run: ide android-studio. Detailed documentation can be found at https://developer.android.com/studio/. cmd.aws=Tool commandlet for AWS CLI. cmd.aws.detail=The AWS Command Line Interface (AWS CLI) is an open source tool for managing AWS resources. Detailed documentation can be found at https://docs.aws.amazon.com/cli/ cmd.az=Tool commandlet for Azure CLI. diff --git a/cli/src/main/resources/nls/Help_de.properties b/cli/src/main/resources/nls/Help_de.properties index 8b47940d4..cc72cb8f5 100644 --- a/cli/src/main/resources/nls/Help_de.properties +++ b/cli/src/main/resources/nls/Help_de.properties @@ -1,6 +1,7 @@ cmd.--version=Gibt die Version von IDEasy aus. cmd.--version.detail=TODO DE --version cmd.android-studio=Werkzeug Kommando für Android Studio (IDE). +cmd.android-studio.detail=Das android-studio Kommando ermöglicht die Installation, Konfiguration und den Start von Android Studio. Um Android Studio für Ihren aktuellen Arbeitsbereich und die IDEasy-Installation zu starten, führen Sie einfach: 'ide android-studio' aus. Detaillierte Dokumentation finden Sie unter https://developer.android.com/studio/. cmd.aws=Werkzeug Kommando für AWS Kommandoschnittstelle. cmd.aws.detail=Das AWS Command Line Interface (AWS CLI) ist ein Open-Source-Werkzeug zur Verwaltung von AWS Ressourcen. Detaillierte Dokumentation ist zu finden unter https://docs.aws.amazon.com/cli/ cmd.az=Werkzeug Kommando für Azure Kommandoschnittstelle. From 4382b436935429f4973cdd8f2267c0bd781d11a4 Mon Sep 17 00:00:00 2001 From: jan-vcapgemini Date: Mon, 8 Jul 2024 12:38:38 +0200 Subject: [PATCH 19/20] #12: removed documentation --- documentation/android-studio.adoc | 52 ------------------------------- 1 file changed, 52 deletions(-) delete mode 100644 documentation/android-studio.adoc diff --git a/documentation/android-studio.adoc b/documentation/android-studio.adoc deleted file mode 100644 index 25f4f366a..000000000 --- a/documentation/android-studio.adoc +++ /dev/null @@ -1,52 +0,0 @@ -:toc: -toc::[] - -= android-studio - -The `android-studio` commandlet allows to install, configure, and launch https://developer.android.com/studio/[Android Studio]. -To launch Android Studio for your current workspace and `IDEasy` installation, simply run: -`ide android-studio` - -There are link:variables.asciidoc[variables] that can be used for Android Studio. -These are explained by the following table: - -.Variables of IDEasy for Android Studio -[options="header"] -|======================= -|*Variable*|*Meaning* -|*`ANDROID_STUDIO_VERSION`* |The version of the tool Android Studio to install and use. -|*`EXTRA_JAVA_VERSION`* |You can set this to a different (newer) version of Java used to launch your IDE (other than `JAVA_VERSION` that is used to build your project) -|======================= - -== plugins - -To be productive with Android Studio you need plugins. -Of course `IDEasy` can automate this for you: -In your link:settings.asciidoc[settings] git repository create a folder https://github.com/devonfw/ide-settings/tree/master/android-studio/plugins[android-studio/plugins] (click this link to see more examples and see which plugins come by default). -Here you can create a properties file for each plugin. -This is an example https://github.com/devonfw/ide-settings/blob/master/android-studio/plugins/asciidoc.properties[scala.properties]: -``` -plugin_id=org.asciidoctor.intellij.asciidoc -plugin_active=false -``` - -The variables are defined as following: - -* `plugin_id` defines the unique ID of the plugin to install. -If you want to customize `IDEasy` with new plugins use the search on https://plugins.jetbrains.com/androidstudio to find the plugin of your choice. -Select the tab `Versions` and click on a version in the list. -The plugin ID is displayed in the upper right corner. -Copy & paste the ID from here to make up your own custom config. -* `plugin_active` is an optional parameter. -If it is `true` (default) the plugin will be installed automatically during the project link:setup.asciidoc[setup] for all developers in your team. -Otherwise, developers can still install the plugin manually via `ide android-studio add-plugin «plugin_id»`. - -In general, you should try to stick with the configuration pre-defined by your project. -But some plugins may be considered as personal flavor and are typically not predefined by the project config. -Such plugins should be shipped with your link:settings.asciidoc[settings] as described above with `plugin_active=false` allowing you to easily install it manually. -Surely, you can easily add plugins via the UI of Android Studio. -However, be aware that some plugins may collect sensitive data or could introduce other vulnerabilities. -So consider the governance of your project and talk to your technical lead before installing additional plugins that are not pre-defined in your link:settings.asciidoc[settings]. - -As maintainer of the link:settings.asciidoc[settings] for your project you should avoid to ship too many plugins that may waste resources but are not used by every developer. -By configuring additional plugins with `plugin_active=false` you can give your developers the freedom to install some additional plugins easily. From 0ecd27e7c1a0d60c1536125addf033fd9846de8d Mon Sep 17 00:00:00 2001 From: jan-vcapgemini Date: Mon, 8 Jul 2024 12:47:44 +0200 Subject: [PATCH 20/20] #25: added missing binary added idea64.exe to gitattributes --- .gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitattributes b/.gitattributes index cb3464431..7e7a79ac6 100644 --- a/.gitattributes +++ b/.gitattributes @@ -9,3 +9,4 @@ # special handling for test files studio64.exe text +idea64.exe text