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
This commit is contained in:
2026-01-21 18:50:37 +01:00
parent 66c17c9cb0
commit 34a9891e44
9 changed files with 516 additions and 0 deletions

View File

@@ -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"
}

View File

@@ -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

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
.task/

3
.taskrc.yml Normal file
View File

@@ -0,0 +1,3 @@
# Enable experimental features
experiments:
REMOTE_TASKFILES: 1

3
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"terminal.integrated.defaultProfile.linux": "zsh"
}

44
Taskfile.yml Normal file
View File

@@ -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

View File

@@ -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"
}

View File

@@ -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

3
template/.taskrc.yml Normal file
View File

@@ -0,0 +1,3 @@
# Enable experimental features
experiments:
REMOTE_TASKFILES: 1