Skip to content
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

Introduce workspace-vscode-base and workspace-vscode-cpp images #11096

Open
wants to merge 65 commits into
base: master
Choose a base branch
from

Conversation

jgfoster
Copy link
Contributor

@jgfoster jgfoster commented Jan 6, 2025

In Slack, @nwalters512 suggested that "We'd definitely like to have a first party VSCode C++ image, and in fact we'd like to get a workspace-vscode-base image or the like that we can build all language-specific images on top of. PRs are welcome if you'd like to contribute either/both of those!"

Now that Python is building again (miniconda issues), I've been able to work on this. This PR represents a (somewhat simplistic) separation of vscode-python into vscode-base, vscode-python, and vscode-cpp. Is this in the general direction you were suggesting? I welcome advice/direction!

Copy link

codecov bot commented Jan 6, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 72.05%. Comparing base (996b4b1) to head (585d280).
Report is 40 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #11096      +/-   ##
==========================================
+ Coverage   72.01%   72.05%   +0.04%     
==========================================
  Files         587      595       +8     
  Lines       95104    95717     +613     
  Branches     7680     7717      +37     
==========================================
+ Hits        68490    68971     +481     
- Misses      26126    26248     +122     
- Partials      488      498      +10     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Contributor

@nwalters512 nwalters512 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for doing this! This seems like broadly the right direction to move in.

You'll need to update our CI process to build and publish these images. There are two relevant workflows:

Take care to build the images in the correct order. That is, you'll need to build ...-base before building ...-python and ...-cpp.

workspaces/vscode-python/requirements.txt Outdated Show resolved Hide resolved
instead of using Microsoft's official VS Code marketplace. Many extensions
are available from Open VSX by the same names, but some extensions might not
be compatible.
This image is a copy of `workspace-vscode-basic` with Python installed.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This image is a copy of `workspace-vscode-basic` with Python installed.
This image is based on `prairielearn/workspace-vscode-base`. It includes Python, an opinionated set of packages, and some Python extensions for VS Code.

I'd also encourage you to link to the ...-base documentation so that users can see details about home directories and such (the problem that you yourself ran into recently on Slack!).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Link added.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be inclined to explicitly say something more like "see [link] for recommended settings when using this workspace in this question", or something like that (please improve as you see fit). We really want people to click that link!

Please make similar changes to the cpp workspace image's readme.

workspaces/vscode-python/Dockerfile Outdated Show resolved Hide resolved
@@ -66,39 +28,15 @@ RUN export arch=`uname -m` \
&& mamba clean --all --yes --quiet \
&& pip cache purge

# Install VS Code extensions and clear the extension cache to reduce image size.
# Install VS Code extensions.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you remove the "...and clear the extension cache" part of the comment and script?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The removal was done in vscode-base and I didn't think that /home/coder/.local/share/code-server/CachedExtensionVSIXs needed to be removed again. but my understanding of extensions and the cache is very limited!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want this to be done after each time an extension is installed, as the cache will be re-populated with stuff whenever a new extension is installed.

workspaces/vscode-cpp/README.md Outdated Show resolved Hide resolved
workspaces/vscode-cpp/README.md Outdated Show resolved Hide resolved
workspaces/vscode-cpp/Dockerfile Show resolved Hide resolved
# Conflicts:
#	workspaces/vscode-python/Dockerfile
@jgfoster
Copy link
Contributor Author

jgfoster commented Jan 7, 2025

Because of the licensing issues, I don't think we can add ms-vscode.cpptools-extension-pack. I've used the workspace for C++ and don't immediately see what should be added. I'm reluctant to just grab a couple random things that I don't understand and throw them in. Actually, when we built our own C++ workspace in a different context we used LLVM and extensions for it. I'm happy to take guidance on this (and anything else!).

@reteps
Copy link
Collaborator

reteps commented Jan 7, 2025

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

Is there another reason you were worried about the licensing of the extension?

@nwalters512
Copy link
Contributor

Additional binary files are included in the official VSIX files built and distributed by Microsoft; these are governed by the more restrictive proprietary license terms found at RuntimeLicenses.

This is the key part of https://github.com/microsoft/vscode-cpptools/blob/main/LICENSE.md

See also https://coder.com/docs/code-server/FAQ#why-cant-code-server-use-microsofts-extension-marketplace - non-VSCode editors can't use extensions published to Microsoft's extension marketplace.

@nwalters512
Copy link
Contributor

@jgfoster for the images to build correctly, you'll need to add something like this (note that the build is currently failing because prairielearn/workspace-vscode-base:latest doesn't exist locally or in Docker Hub):

# This ensures that the `prairielearn/prairielearn` image is built with the
# correct version of `prairielearn/plbase`. We'll only tag this as `latest`
# if we actually built it; if it wasn't built, we don't tag it, so Docker will
# correctly fall back to pulling the `latest` version from the registry.
- name: Tag plbase image as latest
if: ${{ env.images_plbase_modified }}
run: docker tag prairielearn/plbase:${{ env.COMMIT_SHA }} prairielearn/plbase:latest

This should be added after the -base image is built but before -python/-cpp are.

cc @reteps this will have implications for #11102. I'd like you to propose a plan to handle image dependencies like this before we merge that PR.

Copy link
Contributor

@nwalters512 nwalters512 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two more notes:

  • Please add this image to the list of workspace images in the workspace docs:
    ## Maintained workspace images
    PrairieLearn provides and maintains the following workspace images:
    - [`prairielearn/workspace-desktop`](https://github.com/PrairieLearn/PrairieLearn/tree/master/workspaces/desktop/): An Ubuntu 24.04 desktop
    - [`prairielearn/workspace-jupyterlab-python`](https://github.com/PrairieLearn/PrairieLearn/tree/master/workspaces/jupyterlab-python/): JupyterLab with Python 3.11
    - [`prairielearn/workspace-rstudio`](https://github.com/PrairieLearn/PrairieLearn/tree/master/workspaces/rstudio/): RStudio with R version 4.4
    - [`prairielearn/workspace-vscode-python`](https://github.com/PrairieLearn/PrairieLearn/tree/master/workspaces/vscode-python/): VS Code with Python 3.10
    - [`prairielearn/workspace-xtermjs`](https://github.com/PrairieLearn/PrairieLearn/tree/master/workspaces/xtermjs/): Terminal emulator based on xterm.js
  • Please add an example question in exampleCourse. The prairielearn/workspace-vscode-python has an example question here: https://github.com/PrairieLearn/PrairieLearn/tree/master/exampleCourse/questions/demo/workspace/vscode-python. You can hopefully pattern match off that.

After that, this should be more or less ready to go! Just pending input from Jonatan on appropriate extensions to install.

.github/workflows/main.yml Outdated Show resolved Hide resolved
workspaces/vscode-cpp/Dockerfile Outdated Show resolved Hide resolved
workspaces/vscode-cpp/README.md Outdated Show resolved Hide resolved
.github/workflows/main.yml Outdated Show resolved Hide resolved
.github/workflows/images.yml Outdated Show resolved Hide resolved
Comment on lines +25 to +35
# Apt installs: Enable manpages with "unminimize", and common utilities.
USER root
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \
apt-get install -y --no-install-recommends \
man-db unminimize \
gosu curl git htop less nano unzip vim wget zip && \
yes | unminimize && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* && \
find /tmp -not -path /tmp -delete
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original image had these as two separate steps with a cache clean in between:

# Apt installs: Enable manpages with "unminimize", and then install common utilities.
USER root
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \
    apt-get install -y man-db unminimize && \
    yes | unminimize && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/* && \
    find /tmp -not -path /tmp -delete
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
    gosu curl git htop less nano unzip vim wget zip && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/* && \
    find /tmp -not -path /tmp -delete

I opted to combine them, as it's a little faster if we can avoid removing all the cached data in between.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think my logic in installing man first was that if you install it and unminimize after other packages are installed, then some redundant work seems to be done adding their man pages belatedly. So, I thought it would be more efficient to make sure that man and unminimize are done before installing additional stuff.

Copy link
Collaborator

@echuber2 echuber2 Jan 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...Also, I had it as a separate RUN step out in front so that if more packages needed to be added later (in the subsequent RUN step), it would be slightly faster to rebuild. I didn't benchmark any of those hunches, though.

@jonatanschroeder
Copy link
Member

I found a set of extensions that gives a better user experience:

RUN code-server --disable-telemetry --force \
    --install-extension danielpinto8zz6.c-cpp-compile-run \
    --install-extension danielpinto8zz6.c-cpp-project-generator \
    --install-extension KylinIdeTeam.cppdebug \
    --install-extension jeff-hykin.better-cpp-syntax \
    --install-extension ms-vscode.cpptools-themes \
    && rm -rf /home/coder/.local/share/code-server/CachedExtensionVSIXs

This does not include support for Makefile, so it's not perfect, but it has some configurable options for flags and binary name, so it should be good as an MVP.

@nwalters512
Copy link
Contributor

  • danielpinto8zz6.c-cpp-compile-run: this seems to only be useful for single-file projects. I guess some very basic questions might work fine with that?
  • danielpinto8zz6.c-cpp-project-generator: is this needed? I'd imagine most instructors are giving starter files. And if they aren't, what if instructors want students to set something up manually from scratch?
  • KylinIdeTeam.cppdebug: seems probably fine, but I thought the background was interesting: "Kylin" seems to be a Chinese fork of VS Code that's meant to work with Chinese CPU architectures and operating systems: https://portrait.gitee.com/openkylin/kylin-code. It doesn't appear to be open source, or even source available: https://gitee.com/quanzhuo/cpp-debug. Is this a concern?

@echuber2
Copy link
Collaborator

Would this extension be any good instead? https://open-vsx.org/extension/eclipse-cdt/cdt-gdb-vscode

@echuber2
Copy link
Collaborator

@jonatanschroeder
Copy link
Member

The main problem with many of these extensions (including the ones from Eclipse and franneck94) is that they to some extent depend on functionality provided by the VSCode default extensions, which are not available on code-server. I checked the Eclipse extension and the vscode-lldb extension, and they both only provide the debugging functionality, but not the ability to compile the code or even actually launch the debugger itself. I'm playing around with other combinations of extensions to see if I can make these work.

@jonatanschroeder
Copy link
Member

I managed to get a decent user flow while limiting some of the weird extensions involved, and adding support for Makefile. In essence, the extensions are:

RUN curl -fsSL https://github.com/vadimcn/codelldb/releases/download/v1.11.1/codelldb-linux-x64.vsix -o /tmp/codelldb-linux-x64.vsix && \
    code-server --disable-telemetry --force  \
    --install-extension KylinIdeTeam.cppdebug \
    --install-extension jeff-hykin.better-cpp-syntax \
    --install-extension ms-vscode.cpptools-themes \
    --install-extension 13xforever.language-x86-64-assembly \
    --install-extension ms-vscode.makefile-tools \
    --install-extension /tmp/codelldb-linux-x64.vsix \
    && rm -rf /home/coder/.local/share/code-server/CachedExtensionVSIXs /tmp/codelldb-linux-x64.vsix

Then the workspace code includes a .vscode/tasks.json file:

{
    "tasks": [
        {
            "type": "shell",
            "label": "Make",
            "command": "make",
        }
    ],
    "version": "2.0.0"
}

And a .vscode/launch.json file:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "(gdb) Launch",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/main",
            "args": [],
            "cwd": "${fileDirname}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "preLaunchTask": "Make"
        }
    ]
}

I also included a Makefile that compiles the code as needed. This causes the make step to be executed as a task, and debugging automatically runs that task before launching. I assume an instructor should be able to use this as a starting point and configured as needed if it's documented (possibly in README.md and/or as a sample in the example course).

@jonatanschroeder
Copy link
Member

  • danielpinto8zz6.c-cpp-compile-run: this seems to only be useful for single-file projects. I guess some very basic questions might work fine with that?
  • danielpinto8zz6.c-cpp-project-generator: is this needed? I'd imagine most instructors are giving starter files. And if they aren't, what if instructors want students to set something up manually from scratch?

These two are no longer needed if the launch.json and tasks.json files above are included.

It seems the repository (https://gitee.com/quanzhuo/cpp-debug) has, as its last commit, the deletion of its license, which I presume to mean it's not a permissive license. I managed to get away with it, by using the lldb provider for debugging, which provides a pretty good debugging experience as well. My launch.json is now:

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "lldb",
            "request": "launch",
            "name": "Launch",
            "program": "${workspaceFolder}/main",
            "args": [],
            "cwd": "${workspaceFolder}",
            "preLaunchTask": "Make"
        }
    ]
}

tasks.json remains the same as the one above. This no longer requires kylin, so extensions are:

RUN curl -fsSL https://github.com/vadimcn/codelldb/releases/download/v1.11.1/codelldb-linux-x64.vsix -o /tmp/codelldb-linux-x64.vsix && \
    code-server --disable-telemetry --force  \
    --install-extension jeff-hykin.better-cpp-syntax \
    --install-extension ms-vscode.cpptools-themes \
    --install-extension 13xforever.language-x86-64-assembly \
    --install-extension ms-vscode.makefile-tools \
    --install-extension /tmp/codelldb-linux-x64.vsix \
    && rm -rf /home/coder/.local/share/code-server/CachedExtensionVSIXs /tmp/codelldb-linux-x64.vsix

In essence:

  • better-cpp-syntax adds syntax for newer versions of C/C++ that are not supported natively.
  • cpptools-themes adapts to changing themes if a user changes them.
  • language-x86-64-assembly provides assembly language support (needed in many contexts where C is taught). I'm ok with dropping it if it is deemed not needed.
  • makefile-tools adds a context to run individual make targets.
  • codelldb provides the debugging interface and launch option. As mentioned above it needs to be installed via curl because the version on open-vsx downloads an architecture-dependent version from the web on startup, which would be impractical in a network-restricted environment.

Here's a capture:
chrome-capture-2025-0-10

If you're ok with this I can push these changes and a suggested update to README.md with steps instructors are encouraged to use.

@jgfoster
Copy link
Contributor Author

I'm fine with whatever the maintainers want as far as extensions. If we don't settle quickly on a consensus, however, my inclination would be to start with little or nothing just to get the primary feature in, and then deal with extensions as a separate PR. I'd hate for the workspace to get bogged down on extension debates.

@jonatanschroeder
Copy link
Member

@nwalters512 as discussed in the meeting I have added the extensions and documented the files for tasks and launch info. I also added these files to the example course question that @jgfoster has created, and it works fine locally. I decided to skip the Assembly extension, as it's not directly related to C/C++ and instructors have the option of adding it if they wish in a custom image.

Copy link
Member

@jonatanschroeder jonatanschroeder left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested a local build with amd64 and it's building and working as expected. I couldn't test arm64 but I assume @nwalters512 did. In any case, I'd be fine with either merging as is or with the suggested change in retrieving the architecture.

Comment on lines +21 to +24
RUN arch=$(uname -m) && \
if [ "$arch" = "x86_64" ]; then arch="x64"; \
elif [ "$arch" = "aarch64" ]; then arch="arm64"; \
else echo "Unsupported architecture: $arch"; exit 1; fi && \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To double-check what the extension itself uses to identify the platform I checked this:
https://github.com/vadimcn/codelldb/blob/d1ae2ebef7e44ea13d3aa8282f0b0b85d4838b6f/extension/install.ts#L96-L103
https://github.com/vadimcn/codelldb/blob/d1ae2ebef7e44ea13d3aa8282f0b0b85d4838b6f/package.json#L1124-L1135

Since we're working with a guaranteed Linux environment and we're assuming that the build only happens in either amd64 or arm64 I think this approach makes sense, however an alternative option may be to use:

Suggested change
RUN arch=$(uname -m) && \
if [ "$arch" = "x86_64" ]; then arch="x64"; \
elif [ "$arch" = "aarch64" ]; then arch="arm64"; \
else echo "Unsupported architecture: $arch"; exit 1; fi && \
RUN arch=$(/usr/lib/code-server/lib/node -p 'os.arch()') && \

Won't block on this, though.

Copy link
Collaborator

@reteps reteps Jan 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to stick with uname -m for consistency reasons in the rest of our Dockerfiles / shell scripts.

@reteps reteps mentioned this pull request Feb 12, 2025
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants