-
Notifications
You must be signed in to change notification settings - Fork 90
#2337: Docker instance of IDEasy (WIP) #2391
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
cec3bd6
4f38bd9
569fb48
de626c1
e780344
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,198 @@ | ||
| package com.devonfw.tools.ide.commandlet; | ||
|
|
||
| import java.nio.file.Path; | ||
| import java.nio.file.Paths; | ||
|
|
||
| import com.devonfw.tools.ide.context.IdeContext; | ||
| import com.devonfw.tools.ide.property.BooleanProperty; | ||
|
|
||
| /** | ||
| * {@link Commandlet} to print the environment variables. | ||
| */ | ||
| public class ContainerCommandlet extends Commandlet { | ||
|
|
||
| private static final String IMAGE_NAME = "ideasy-linux"; | ||
|
|
||
| private final BooleanProperty rebuild; | ||
|
|
||
| /** | ||
| * The constructor. | ||
| * | ||
| * @param context the {@link IdeContext}. | ||
| */ | ||
| public ContainerCommandlet(IdeContext context) { | ||
|
|
||
| super(context); | ||
|
|
||
| addKeyword("container"); | ||
|
|
||
| this.rebuild = add(new BooleanProperty("--rebuild", false, "-r")); | ||
| } | ||
|
|
||
| @Override | ||
| public String getName() { | ||
|
|
||
| return "container"; | ||
| } | ||
|
|
||
| @Override | ||
| protected void doRun() { | ||
|
|
||
| try { | ||
|
|
||
| verifyDocker(); | ||
| verifySshAgent(); | ||
|
|
||
| Path dockerfile = Paths.get("IDEasy", "docker", "Dockerfile").toAbsolutePath(); | ||
| Path buildContext = Paths.get("IDEasy").toAbsolutePath(); | ||
|
|
||
| if (Boolean.TRUE.equals(this.rebuild.getValue())) { | ||
| removeImage(); | ||
| } | ||
|
|
||
| if (!imageExists()) { | ||
| buildImage( | ||
| toWslPath(dockerfile), | ||
| toWslPath(buildContext)); | ||
| } | ||
| startContainer(); | ||
|
|
||
| } catch (Exception e) { | ||
|
|
||
| throw new RuntimeException(e); | ||
| } | ||
| } | ||
|
|
||
| private void verifyDocker() throws Exception { | ||
|
|
||
| int exitCode = runAndWaitSilent( | ||
| "wsl", | ||
| "docker", | ||
| "--version"); | ||
|
|
||
| if (exitCode != 0) { | ||
| throw new IllegalStateException("Docker is not available."); | ||
| } | ||
| } | ||
|
|
||
| private void verifySshAgent() throws Exception { | ||
|
|
||
| int exitCode = runAndWaitSilent( | ||
| "C:\\Windows\\System32\\OpenSSH\\ssh-add.exe", | ||
| "-l"); | ||
|
|
||
| if (exitCode != 0) { | ||
|
|
||
| throw new IllegalStateException( | ||
| "No SSH identity loaded in Windows OpenSSH agent."); | ||
| } | ||
| } | ||
|
|
||
| private boolean imageExists() throws Exception { | ||
|
|
||
| return runAndWaitSilent( | ||
| "wsl", | ||
| "docker", | ||
| "image", | ||
| "inspect", | ||
| IMAGE_NAME) == 0; | ||
| } | ||
|
|
||
| private void removeImage() throws Exception { | ||
|
|
||
| runAndWaitSilent( | ||
| "wsl", | ||
| "docker", | ||
| "rmi", | ||
| "-f", | ||
| IMAGE_NAME); | ||
| } | ||
|
|
||
| private void buildImage(String dockerfile, String context) throws Exception { | ||
|
|
||
| int exitCode = runAndWait( | ||
| "wsl", | ||
| "docker", | ||
| "build", | ||
| "-t", | ||
| IMAGE_NAME, | ||
| "-f", | ||
| dockerfile, | ||
| context); | ||
|
|
||
| if (exitCode != 0) { | ||
|
|
||
| throw new RuntimeException( | ||
| "Docker build failed with exit code " + exitCode); | ||
| } | ||
| } | ||
|
|
||
| private String getWslHome() throws Exception { | ||
|
|
||
| Process process = new ProcessBuilder( | ||
| "wsl", | ||
| "sh", | ||
| "-c", | ||
| "printf $HOME") | ||
| .start(); | ||
|
|
||
| return new String(process.getInputStream().readAllBytes()).trim(); | ||
| } | ||
|
|
||
| private void startContainer() throws Exception { | ||
|
|
||
| String wslHome = getWslHome(); | ||
|
|
||
| new ProcessBuilder( | ||
| "cmd", | ||
| "/c", | ||
| "start", | ||
| "wsl", | ||
| "docker", | ||
| "run", | ||
| "--rm", | ||
| "-it", | ||
|
|
||
| "-e", "DISPLAY", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. WSLg/display env is non-functional (156-162 )l: -e DISPLAY/WAYLAND_DISPLAY/XDG_RUNTIME_DIR read Windows values that don't work inside WSL. |
||
| "-e", "WAYLAND_DISPLAY", | ||
| "-e", "XDG_RUNTIME_DIR", | ||
| "-e", "PULSE_SERVER", | ||
|
|
||
| "-v", "/tmp/.X11-unix:/tmp/.X11-unix", | ||
| "-v", "/mnt/wslg:/mnt/wslg", | ||
|
|
||
| "-v", wslHome + "/.ssh:/root/.ssh", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ~/.ssh mounted but permissions not normalized, no chmod 700/600; Linux OpenSSH refuses world-readable/foreign-uid keys. |
||
|
|
||
| "-v", "ideasy-data:/projects", | ||
| "-v", "ideasy-home:/root", | ||
|
|
||
| IMAGE_NAME) | ||
| .start(); | ||
| } | ||
|
|
||
| private int runAndWait(String... command) throws Exception { | ||
|
|
||
| ProcessBuilder pb = new ProcessBuilder(command); | ||
|
|
||
| pb.inheritIO(); | ||
|
|
||
| return pb.start().waitFor(); | ||
| } | ||
|
|
||
| private int runAndWaitSilent(String... command) throws Exception { | ||
|
|
||
| ProcessBuilder pb = new ProcessBuilder(command); | ||
|
|
||
| pb.redirectOutput(ProcessBuilder.Redirect.DISCARD); | ||
| pb.redirectError(ProcessBuilder.Redirect.DISCARD); | ||
|
|
||
| return pb.start().waitFor(); | ||
| } | ||
|
|
||
| private String toWslPath(Path path) { | ||
|
|
||
| return path.toString() | ||
| .replace("\\", "/") | ||
| .replace("C:", "/mnt/c"); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| FROM ubuntu:24.04 | ||
| ARG IDEASY_VERSION=2026.08.001 | ||
| ENV IDE_ROOT=/projects | ||
| RUN apt-get update \ | ||
| && apt-get install -y --no-install-recommends \ | ||
| ca-certificates \ | ||
| curl \ | ||
| git \ | ||
| gzip \ | ||
| tar \ | ||
| bash \ | ||
| libfreetype6 \ | ||
| fontconfig \ | ||
| libx11-6 \ | ||
| libxext6 \ | ||
| libxrender1 \ | ||
| libxtst6 \ | ||
| libxi6 \ | ||
| libxrandr2 \ | ||
| libxinerama1 \ | ||
| libxcursor1 \ | ||
| libxcomposite1 \ | ||
| libxdamage1 \ | ||
| openssh-client \ | ||
| libgtk-3-0 \ | ||
| libglib2.0-0 \ | ||
| libatk1.0-0 \ | ||
| libatk-bridge2.0-0 \ | ||
| libcairo2 \ | ||
| libpango-1.0-0 \ | ||
| libgdk-pixbuf-2.0-0 \ | ||
| libnss3 \ | ||
| libgbm1 \ | ||
| libasound2t64 \ | ||
| && rm -rf /var/lib/apt/lists/* | ||
|
|
||
| # GitHub Copilot CLI | ||
|
|
||
| RUN apt-get update \ | ||
| && apt-get install -y nodejs npm \ | ||
| && npm install -g @github/copilot \ | ||
| && rm -rf /var/lib/apt/lists/* | ||
|
|
||
| # IDEasy | ||
|
|
||
| RUN mkdir -p /opt/ideasy "${IDE_ROOT}" \ | ||
| && curl -fsSL \ | ||
| "https://repo1.maven.org/maven2/com/devonfw/tools/IDEasy/ide-cli/${IDEASY_VERSION}/ide-cli-${IDEASY_VERSION}-linux-x64.tar.gz" \ | ||
| -o /tmp/ideasy.tar.gz \ | ||
| && tar --extract --gzip --no-same-owner \ | ||
| --file /tmp/ideasy.tar.gz \ | ||
| --directory /opt/ideasy \ | ||
| && cd /opt/ideasy \ | ||
| && ./bin/ideasy --batch --force install \ | ||
| && rm /tmp/ideasy.tar.gz | ||
|
|
||
| ENV PATH="${IDE_ROOT}/_ide/installation/bin:${PATH}" | ||
|
|
||
| RUN ideasy --batch create basic-project - | ||
|
|
||
| WORKDIR /projects/basic-project | ||
|
|
||
| CMD ["bash"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SSH agent checked but not forwarded:
verifySshAgent()only checks the Windows OpenSSH agent; the container gets neither SSH_AUTH_SOCK nor a socket mount.