From 34a9891e445ac099820234fb3d93acdc0a0b79dc Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 21 Jan 2026 18:50:37 +0100 Subject: [PATCH] Add initial DevContainer setup and configuration files - Create .devcontainer/devcontainer.json for container environment setup - Add postStartCommand.sh for provisioning system dependencies and configuration - Include .gitignore to exclude task-related files - Create .taskrc.yml to enable experimental features - Add Taskfile.yml for task management and configuration - Set up VSCode settings for integrated terminal using zsh --- .devcontainer/devcontainer.json | 51 ++++++ .devcontainer/postStartCommand.sh | 180 +++++++++++++++++++++ .gitignore | 1 + .taskrc.yml | 3 + .vscode/settings.json | 3 + Taskfile.yml | 44 +++++ template/.devcontainer/devcontainer.json | 51 ++++++ template/.devcontainer/postStartCommand.sh | 180 +++++++++++++++++++++ template/.taskrc.yml | 3 + 9 files changed, 516 insertions(+) create mode 100644 .devcontainer/devcontainer.json create mode 100644 .devcontainer/postStartCommand.sh create mode 100644 .gitignore create mode 100644 .taskrc.yml create mode 100644 .vscode/settings.json create mode 100644 Taskfile.yml create mode 100644 template/.devcontainer/devcontainer.json create mode 100644 template/.devcontainer/postStartCommand.sh create mode 100644 template/.taskrc.yml diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..42eb5a8 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,51 @@ +{ + "image": "ubuntu:24.04", + "containerEnv": { + "CONAN_USR": "", // need to be filled + "CONAN_PSW": "" // need to be filled, + }, + "features": { + "ghcr.io/devcontainers/features/git:1": {}, + "ghcr.io/devcontainers/features/git-lfs:1": {}, + "ghcr.io/devcontainers/features/python:1": { + "toolsToInstall": "flake8,autopep8,black,yapf,mypy,pydocstyle,pycodestyle,bandit,pipenv,virtualenv,pytest,pylint,uv,copier,conan" + } + }, + "customizations": { + "vscode": { + "settings": { + "git.path": "/usr/bin/git" + }, + "extensions": [ + "ms-python.python", + "ms-python.vscode-pylance", + "GitHub.copilot-chat", + "njqdev.vscode-python-typehint", + "ms-python.debugpy", + "mhutchie.git-graph", + "ms-vscode.cpptools-themes", + "tamasfe.even-better-toml", + "moshfeu.compare-folders", + "njpwerner.autodocstring", + "ms-python.black-formatter", + "ms-python.isort", + "ms-vscode.live-server", + "yzhang.markdown-all-in-one", + "bierner.markdown-mermaid", + "charliermarsh.ruff", + "shardulm94.trailing-spaces", + "redhat.vscode-yaml", + "ninoseki.vscode-mogami", + "twxs.cmake", + "cheshirekow.cmake-format", + "wholroyd.jinja" + ] + } + }, + "runArgs": [ + "--network=host", + "-e HOST_UID=$(id -u)", + "-e HOST_GID=$(id -g)" + ], + "postStartCommand": ".devcontainer/postStartCommand.sh" +} diff --git a/.devcontainer/postStartCommand.sh b/.devcontainer/postStartCommand.sh new file mode 100644 index 0000000..70c90a2 --- /dev/null +++ b/.devcontainer/postStartCommand.sh @@ -0,0 +1,180 @@ +#!/bin/bash + +# ============================================================================== +# Conan2 Development Environment Setup +# +# Description: Provisions system dependencies, shell configuration, and Conan2. +# Designed for Debian/Ubuntu-based DevContainers or CI Runners. +# Usage: CONAN_USR=x CONAN_PSW=y ./postStartCommand.sh +# ============================================================================== + +set -euo pipefail + +# --- Configuration ------------------------------------------------------------ +# Versions & Remote Resources +TASK_VERSION="v3.45.5" +GLOW_VERSION="2.1.1" +CONAN_CONFIG_URL="https://package-cloud.dns.army/ros2/conan2-config.git" +CONAN_REMOTE_NAME="package-cloud-ros2-conan2" + +# Localization +TIMEZONE="Europe/Berlin" + +# Paths +LOCAL_BIN="$HOME/.local/bin" +ZSH_CUSTOM="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}" + +# --- Helpers ------------------------------------------------------------------ + +log() { + echo -e "\033[1;34m>>> [SETUP] $1\033[0m" +} + +error() { + echo -e "\033[1;31m!!! [ERROR] $1\033[0m" >&2 + exit 1 +} + +cleanup() { + # Remove temp files on exit (successful or not) + rm -f glow.deb install_task.sh +} +trap cleanup EXIT + +ensure_env_vars() { + if [[ -z "${CONAN_USR:-}" ]] || [[ -z "${CONAN_PSW:-}" ]]; then + error "CONAN_USR and CONAN_PSW environment variables are required." + fi +} + +detect_arch() { + local arch + arch=$(dpkg --print-architecture) + case "$arch" in + amd64) echo "amd64" ;; + arm64) echo "arm64" ;; + *) error "Unsupported architecture: $arch" ;; + esac +} + +# --- Installation Functions --------------------------------------------------- + +install_system_dependencies() { + log "Installing system dependencies..." + export DEBIAN_FRONTEND=noninteractive + + apt-get update -q + apt-get install -y -q --no-install-recommends \ + tzdata curl git zsh python3 python3-pip python3-venv \ + ca-certificates gnupg pipx + + # Ensure pipx path is available immediately for this script + export PATH="$LOCAL_BIN:$PATH" + pipx ensurepath +} + +configure_timezone() { + log "Configuring timezone ($TIMEZONE)..." + local tz_path="/usr/share/zoneinfo/$TIMEZONE" + + # Validation: Ensure the requested timezone actually exists + if [ ! -f "$tz_path" ]; then + error "Timezone data not found at '$tz_path'. Please check the TIMEZONE variable." + fi + + ln -fs "$tz_path" /etc/localtime + echo "$TIMEZONE" >/etc/timezone + dpkg-reconfigure -f noninteractive tzdata +} + +install_shell_tools() { + log "Setting up Shell (Oh My Zsh)..." + if [ ! -d "$HOME/.oh-my-zsh" ]; then + sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended + else + log "Oh My Zsh already installed. Skipping." + fi +} + +install_conan() { + log "Installing Conan via pipx (Isolated)..." + + # Config + log "Installing Conan Config..." + # Force allows overwriting existing configs which is usually desired in setup scripts + conan config install "$CONAN_CONFIG_URL" --type git --args="--branch main" + + log "Authenticating Conan..." + conan remote login "$CONAN_REMOTE_NAME" "$CONAN_USR" -p "$CONAN_PSW" +} + +install_utilities() { + local arch + arch=$(detect_arch) + + # 1. Taskfile + log "Installing Taskfile ($TASK_VERSION)..." + curl -sL -o install_task.sh https://taskfile.dev/install.sh + sh install_task.sh -d -b "$LOCAL_BIN" "$TASK_VERSION" + + # 2. Glow + log "Installing Glow ($GLOW_VERSION for $arch)..." + local glow_url="https://github.com/charmbracelet/glow/releases/download/v${GLOW_VERSION}/glow_${GLOW_VERSION}_${arch}.deb" + + curl -L -o glow.deb "$glow_url" + dpkg -i glow.deb +} + +configure_persistence() { + log "Persisting configurations..." + + local zshrc="$HOME/.zshrc" + touch "$zshrc" + + # Helper to append if missing + append_if_missing() { + local file="$1" + local content="$2" + if ! grep -Fxq "$content" "$file"; then + echo "$content" >>"$file" + fi + } + + # Add Local Bin to Path + local path_export='export PATH="$HOME/.local/bin:$PATH"' + append_if_missing "$HOME/.bashrc" "$path_export" + append_if_missing "$zshrc" "$path_export" + + # Shell Completions + append_if_missing "$zshrc" 'eval "$(task --completion zsh)"' + append_if_missing "$zshrc" 'eval "$(glow completion zsh)"' + + # Git Safe Directory + git config --global --add safe.directory /workspaces/conan2-ros2-hesai-lidar +} + +run_tasks() { + if [ -f "Taskfile.yml" ] || [ -f "Taskfile.yaml" ]; then + log "Running default Task..." + "$LOCAL_BIN/task" --yes + else + log "No Taskfile found. Skipping 'task --yes'." + fi +} + +# --- Main Execution ----------------------------------------------------------- + +main() { + ensure_env_vars + install_system_dependencies + configure_timezone + install_shell_tools + install_utilities # Task & Glow + install_conan + configure_persistence + run_tasks + + log "Setup complete successfully." +} + +main diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fcdbb07 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.task/ \ No newline at end of file diff --git a/.taskrc.yml b/.taskrc.yml new file mode 100644 index 0000000..a3e9652 --- /dev/null +++ b/.taskrc.yml @@ -0,0 +1,3 @@ +# Enable experimental features +experiments: + REMOTE_TASKFILES: 1 \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..55ec6c8 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "terminal.integrated.defaultProfile.linux": "zsh" +} \ No newline at end of file diff --git a/Taskfile.yml b/Taskfile.yml new file mode 100644 index 0000000..d45b087 --- /dev/null +++ b/Taskfile.yml @@ -0,0 +1,44 @@ +# https://taskfile.dev + +version: "3" + +vars: + # Global Configuration + CONAN2_CONFIG_URL: https://package-cloud.dns.army/ros2/conan2-config + CONAN2_CONFIG_BRANCH: main + CONAN2_CONFIG_TASKFILE_PATH: Taskfile.yml + CONAN_BUILD_VERSION: latest + +includes: + # Remote includes + conan2-config: "{{.CONAN2_CONFIG_URL}}/raw/branch/{{.CONAN2_CONFIG_BRANCH}}/{{.CONAN2_CONFIG_TASKFILE_PATH}}" + + # Local modules + +tasks: + default: + desc: Show available tasks + silent: true + cmds: + - task: version + - task --list + + version: + desc: Display component version information + silent: true + vars: + NAME_COMPONENT: repo-templates + URL_COMPONENT: https://package-cloud.dns.army/ros2/repo-templates + GIT_SHA: + sh: git rev-parse --short HEAD + GIT_REF: + sh: git rev-parse --abbrev-ref HEAD + cmds: + - printf "{{.B_MAGENTA}}Component{{.RESET}} - {{.CYAN}}{{.NAME_COMPONENT}}{{.RESET}}\n" + - printf "{{.B_MAGENTA}}URL{{.RESET}} - {{.CYAN}}{{.URL_COMPONENT}}{{.RESET}}\n" + - printf "{{.B_MAGENTA}}Branch{{.RESET}} - {{.CYAN}}{{.GIT_REF}} {{.B_WHITE}}{{.RESET}} - {{.B_MAGENTA}}Hash{{.RESET}} - {{.GREEN}}{{.GIT_SHA}}{{.RESET}}\n" + + init: + desc: Sync dependencies + cmds: + - uv sync diff --git a/template/.devcontainer/devcontainer.json b/template/.devcontainer/devcontainer.json new file mode 100644 index 0000000..42eb5a8 --- /dev/null +++ b/template/.devcontainer/devcontainer.json @@ -0,0 +1,51 @@ +{ + "image": "ubuntu:24.04", + "containerEnv": { + "CONAN_USR": "", // need to be filled + "CONAN_PSW": "" // need to be filled, + }, + "features": { + "ghcr.io/devcontainers/features/git:1": {}, + "ghcr.io/devcontainers/features/git-lfs:1": {}, + "ghcr.io/devcontainers/features/python:1": { + "toolsToInstall": "flake8,autopep8,black,yapf,mypy,pydocstyle,pycodestyle,bandit,pipenv,virtualenv,pytest,pylint,uv,copier,conan" + } + }, + "customizations": { + "vscode": { + "settings": { + "git.path": "/usr/bin/git" + }, + "extensions": [ + "ms-python.python", + "ms-python.vscode-pylance", + "GitHub.copilot-chat", + "njqdev.vscode-python-typehint", + "ms-python.debugpy", + "mhutchie.git-graph", + "ms-vscode.cpptools-themes", + "tamasfe.even-better-toml", + "moshfeu.compare-folders", + "njpwerner.autodocstring", + "ms-python.black-formatter", + "ms-python.isort", + "ms-vscode.live-server", + "yzhang.markdown-all-in-one", + "bierner.markdown-mermaid", + "charliermarsh.ruff", + "shardulm94.trailing-spaces", + "redhat.vscode-yaml", + "ninoseki.vscode-mogami", + "twxs.cmake", + "cheshirekow.cmake-format", + "wholroyd.jinja" + ] + } + }, + "runArgs": [ + "--network=host", + "-e HOST_UID=$(id -u)", + "-e HOST_GID=$(id -g)" + ], + "postStartCommand": ".devcontainer/postStartCommand.sh" +} diff --git a/template/.devcontainer/postStartCommand.sh b/template/.devcontainer/postStartCommand.sh new file mode 100644 index 0000000..70c90a2 --- /dev/null +++ b/template/.devcontainer/postStartCommand.sh @@ -0,0 +1,180 @@ +#!/bin/bash + +# ============================================================================== +# Conan2 Development Environment Setup +# +# Description: Provisions system dependencies, shell configuration, and Conan2. +# Designed for Debian/Ubuntu-based DevContainers or CI Runners. +# Usage: CONAN_USR=x CONAN_PSW=y ./postStartCommand.sh +# ============================================================================== + +set -euo pipefail + +# --- Configuration ------------------------------------------------------------ +# Versions & Remote Resources +TASK_VERSION="v3.45.5" +GLOW_VERSION="2.1.1" +CONAN_CONFIG_URL="https://package-cloud.dns.army/ros2/conan2-config.git" +CONAN_REMOTE_NAME="package-cloud-ros2-conan2" + +# Localization +TIMEZONE="Europe/Berlin" + +# Paths +LOCAL_BIN="$HOME/.local/bin" +ZSH_CUSTOM="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}" + +# --- Helpers ------------------------------------------------------------------ + +log() { + echo -e "\033[1;34m>>> [SETUP] $1\033[0m" +} + +error() { + echo -e "\033[1;31m!!! [ERROR] $1\033[0m" >&2 + exit 1 +} + +cleanup() { + # Remove temp files on exit (successful or not) + rm -f glow.deb install_task.sh +} +trap cleanup EXIT + +ensure_env_vars() { + if [[ -z "${CONAN_USR:-}" ]] || [[ -z "${CONAN_PSW:-}" ]]; then + error "CONAN_USR and CONAN_PSW environment variables are required." + fi +} + +detect_arch() { + local arch + arch=$(dpkg --print-architecture) + case "$arch" in + amd64) echo "amd64" ;; + arm64) echo "arm64" ;; + *) error "Unsupported architecture: $arch" ;; + esac +} + +# --- Installation Functions --------------------------------------------------- + +install_system_dependencies() { + log "Installing system dependencies..." + export DEBIAN_FRONTEND=noninteractive + + apt-get update -q + apt-get install -y -q --no-install-recommends \ + tzdata curl git zsh python3 python3-pip python3-venv \ + ca-certificates gnupg pipx + + # Ensure pipx path is available immediately for this script + export PATH="$LOCAL_BIN:$PATH" + pipx ensurepath +} + +configure_timezone() { + log "Configuring timezone ($TIMEZONE)..." + local tz_path="/usr/share/zoneinfo/$TIMEZONE" + + # Validation: Ensure the requested timezone actually exists + if [ ! -f "$tz_path" ]; then + error "Timezone data not found at '$tz_path'. Please check the TIMEZONE variable." + fi + + ln -fs "$tz_path" /etc/localtime + echo "$TIMEZONE" >/etc/timezone + dpkg-reconfigure -f noninteractive tzdata +} + +install_shell_tools() { + log "Setting up Shell (Oh My Zsh)..." + if [ ! -d "$HOME/.oh-my-zsh" ]; then + sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended + else + log "Oh My Zsh already installed. Skipping." + fi +} + +install_conan() { + log "Installing Conan via pipx (Isolated)..." + + # Config + log "Installing Conan Config..." + # Force allows overwriting existing configs which is usually desired in setup scripts + conan config install "$CONAN_CONFIG_URL" --type git --args="--branch main" + + log "Authenticating Conan..." + conan remote login "$CONAN_REMOTE_NAME" "$CONAN_USR" -p "$CONAN_PSW" +} + +install_utilities() { + local arch + arch=$(detect_arch) + + # 1. Taskfile + log "Installing Taskfile ($TASK_VERSION)..." + curl -sL -o install_task.sh https://taskfile.dev/install.sh + sh install_task.sh -d -b "$LOCAL_BIN" "$TASK_VERSION" + + # 2. Glow + log "Installing Glow ($GLOW_VERSION for $arch)..." + local glow_url="https://github.com/charmbracelet/glow/releases/download/v${GLOW_VERSION}/glow_${GLOW_VERSION}_${arch}.deb" + + curl -L -o glow.deb "$glow_url" + dpkg -i glow.deb +} + +configure_persistence() { + log "Persisting configurations..." + + local zshrc="$HOME/.zshrc" + touch "$zshrc" + + # Helper to append if missing + append_if_missing() { + local file="$1" + local content="$2" + if ! grep -Fxq "$content" "$file"; then + echo "$content" >>"$file" + fi + } + + # Add Local Bin to Path + local path_export='export PATH="$HOME/.local/bin:$PATH"' + append_if_missing "$HOME/.bashrc" "$path_export" + append_if_missing "$zshrc" "$path_export" + + # Shell Completions + append_if_missing "$zshrc" 'eval "$(task --completion zsh)"' + append_if_missing "$zshrc" 'eval "$(glow completion zsh)"' + + # Git Safe Directory + git config --global --add safe.directory /workspaces/conan2-ros2-hesai-lidar +} + +run_tasks() { + if [ -f "Taskfile.yml" ] || [ -f "Taskfile.yaml" ]; then + log "Running default Task..." + "$LOCAL_BIN/task" --yes + else + log "No Taskfile found. Skipping 'task --yes'." + fi +} + +# --- Main Execution ----------------------------------------------------------- + +main() { + ensure_env_vars + install_system_dependencies + configure_timezone + install_shell_tools + install_utilities # Task & Glow + install_conan + configure_persistence + run_tasks + + log "Setup complete successfully." +} + +main diff --git a/template/.taskrc.yml b/template/.taskrc.yml new file mode 100644 index 0000000..a3e9652 --- /dev/null +++ b/template/.taskrc.yml @@ -0,0 +1,3 @@ +# Enable experimental features +experiments: + REMOTE_TASKFILES: 1 \ No newline at end of file -- 2.43.0