Add tooling for GitHub Codespaces

With this, a new user can fork Rustlings and start a Github Codespace.  The Container will already be correctly set up with everything needed, and VSCode tasks are set up for starting rustlings.
This commit is contained in:
Jeff Bailey 2025-09-13 21:59:46 +00:00
parent 2af9e89ba5
commit 8e99ca9c0c
4 changed files with 269 additions and 0 deletions

41
.devcontainer/Dockerfile Normal file
View File

@ -0,0 +1,41 @@
# Use the official Rust image as base
FROM mcr.microsoft.com/devcontainers/rust:1-1-bullseye
# Set the minimum required Rust version for Rustlings
ENV RUST_VERSION=1.88.0
ENV RUSTUP_HOME=/usr/local/rustup
ENV PATH=/usr/local/rustup/bin:$PATH
# Install the specific Rust version and required components
RUN rustup install ${RUST_VERSION} \
&& rustup default ${RUST_VERSION} \
&& rustup component add clippy rustfmt rust-src \
&& rustup --version \
&& rustc --version \
&& cargo --version \
&& cargo clippy --version
# Install additional useful tools for Rust development
RUN apt-get update && apt-get install -y \
# Git for version control (should already be installed but ensuring it's present)
git \
# Build essentials for any native dependencies
build-essential \
# Tools for debugging and profiling
gdb \
valgrind \
# Text processing tools that might be useful for Rustlings
jq \
tree \
# Clean up apt cache to reduce image size
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Set up the workspace directory
WORKDIR /workspaces/rustlings
# Verify the installation works correctly
RUN rustc --version \
&& cargo --version \
&& clippy-driver --version \
&& rustfmt --version

View File

@ -0,0 +1,58 @@
{
"name": "Rustlings Development Environment",
"build": {
"dockerfile": "Dockerfile",
"context": "."
},
// Features to add to the dev container. More info: https://containers.dev/features.
"features": {
"ghcr.io/devcontainers/features/git:1": {
"ppa": true,
"version": "latest"
}
},
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": {
"setup-tools": "rustc --version && cargo --version && rustup component add clippy rustfmt",
"validate": ".devcontainer/validate.sh",
"setup-welcome": "echo 'echo \"🦀 Welcome to the Rustlings development environment!\"' >> ~/.bashrc && echo 'echo \"Rust version: $(rustc --version)\"' >> ~/.bashrc && echo 'echo \"Ready to start learning Rust with Rustlings!\"' >> ~/.bashrc"
},
// Configure tool-specific properties.
"customizations": {
"vscode": {
"extensions": [
"rust-lang.rust-analyzer"
],
"settings": {
"rust-analyzer.cargo.buildScripts.enable": true,
"rust-analyzer.procMacro.enable": true,
"editor.formatOnSave": true,
"editor.tabSize": 4,
"editor.insertSpaces": true,
"files.trimTrailingWhitespace": true,
"files.insertFinalNewline": true,
"terminal.integrated.defaultProfile.linux": "bash",
"[rust]": {
"editor.defaultFormatter": null
}
}
}
},
// Set container environment variables
"containerEnv": {
"RUSTLINGS_DEV_MODE": "1"
},
// Port forwarding for any potential web servers or debugging
"forwardPorts": [
8080,
3000
],
// Lifecycle scripts
"onCreateCommand": {
"install-tools": "rustup component add clippy rustfmt && rustup update"
},
// Mount the workspace to preserve file permissions and git configuration
"mounts": [
"source=${localWorkspaceFolder}/.git,target=${containerWorkspaceFolder}/.git,type=bind,consistency=cached"
]
}

75
.devcontainer/validate.sh Executable file
View File

@ -0,0 +1,75 @@
#!/bin/bash
# Devcontainer validation script for Rustlings
# This script tests that all required tools are available and working
set -e
echo "🦀 Validating Rustlings Devcontainer Setup..."
echo "=============================================="
# Check Rust toolchain
echo "✓ Checking Rust toolchain..."
rustc --version
cargo --version
# Check minimum Rust version (1.88+)
RUST_VERSION=$(rustc --version | sed 's/rustc \([0-9]\+\.[0-9]\+\).*/\1/')
REQUIRED_VERSION="1.88"
if [ "$(printf '%s\n' "$REQUIRED_VERSION" "$RUST_VERSION" | sort -V | head -n1)" = "$REQUIRED_VERSION" ]; then
echo " ✓ Rust version $RUST_VERSION meets requirement (≥ $REQUIRED_VERSION)"
else
echo " ✗ Rust version $RUST_VERSION does not meet requirement (≥ $REQUIRED_VERSION)"
exit 1
fi
# Check required components
echo "✓ Checking required Rust components..."
rustup component list --installed | grep -q "clippy" && echo " ✓ Clippy is installed"
rustup component list --installed | grep -q "rustfmt" && echo " ✓ rustfmt is installed"
# Test clippy works
echo "✓ Testing Clippy..."
clippy-driver --version > /dev/null && echo " ✓ Clippy is functional"
# Test rustfmt works
echo "✓ Testing rustfmt..."
rustfmt --version > /dev/null && echo " ✓ rustfmt is functional"
# Check Git
echo "✓ Checking Git..."
git --version > /dev/null && echo " ✓ Git is installed"
# Test basic Rust compilation
echo "✓ Testing Rust compilation..."
cd /tmp
cargo init --name test_project > /dev/null 2>&1
cd test_project
cargo check > /dev/null 2>&1 && echo " ✓ Rust compilation works"
cd .. && rm -rf test_project
# Check if we're in the Rustlings workspace
echo "✓ Checking Rustlings workspace..."
if [ -f "/workspaces/rustlings/Cargo.toml" ]; then
echo " ✓ Rustlings workspace is mounted correctly"
cd /workspaces/rustlings
# Test Rustlings build
echo "✓ Testing Rustlings build..."
cargo check > /dev/null 2>&1 && echo " ✓ Rustlings compiles successfully"
# Test Rustlings clippy
echo "✓ Testing Rustlings clippy..."
cargo clippy -- --deny warnings > /dev/null 2>&1 && echo " ✓ Rustlings passes clippy checks"
else
echo " ⚠ Rustlings workspace not found at expected path"
fi
echo ""
echo "🎉 Devcontainer validation completed successfully!"
echo "Ready to start learning Rust with Rustlings!"
echo ""
echo "Try running:"
echo " cargo run -- init # Initialize exercises"
echo " cargo run -- watch # Start watching for changes"

95
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,95 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Start Rustlings",
"type": "shell",
"command": "cargo",
"args": [
"run"
],
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"reveal": "always",
"panel": "new",
"clear": true
},
"options": {
"cwd": "${workspaceFolder}"
},
"problemMatcher": []
},
{
"label": "Rustlings: Run Exercise",
"type": "shell",
"command": "cargo",
"args": [
"run",
"--",
"run",
"${input:exerciseName}"
],
"group": "build",
"presentation": {
"reveal": "always",
"panel": "shared"
},
"options": {
"cwd": "${workspaceFolder}"
},
"problemMatcher": []
},
{
"label": "Rustlings: Get Hint",
"type": "shell",
"command": "cargo",
"args": [
"run",
"--",
"hint",
"${input:exerciseName}"
],
"group": "build",
"presentation": {
"reveal": "always",
"panel": "shared"
},
"options": {
"cwd": "${workspaceFolder}"
},
"problemMatcher": []
},
{
"label": "Rustlings: Reset Exercise",
"type": "shell",
"command": "cargo",
"args": [
"run",
"--",
"reset",
"${input:exerciseName}"
],
"group": "build",
"presentation": {
"reveal": "always",
"panel": "shared"
},
"options": {
"cwd": "${workspaceFolder}"
},
"problemMatcher": []
}
],
"inputs": [
{
"id": "exerciseName",
"description": "Exercise name (e.g., variables1, functions2)",
"default": "",
"type": "promptString"
}
]
}