1+ # Configuration
12SANDBOX_DIR = .sandbox
3+ SANDBOX_ANSWERS_FILE = $(SANDBOX_DIR ) /answers.yml
4+ COPIER_VENV = .venv-tools
5+ COPIER_BIN = $(COPIER_VENV ) /bin/copier
26FEATURES ?= shell
37IMAGE ?= ubuntu:latest
48IMAGES = ubuntu:latest debian:latest amazonlinux:2023 mcr.microsoft.com/devcontainers/base:ubuntu
9+ ANSWERS_FILE = .copier-answers.yml
510
6- .PHONY : help sandbox clean build up rebuild exec stop logs interactive
11+ .PHONY : help sandbox clean build up rebuild exec stop logs interactive ensure-copier format validate
712
13+ # Help Documentation
814help :
915 @echo " "
10- @echo " \033[1;36mAvailable make commands:\033[0m"
11- @echo " --------------------------------------"
12- @echo " \033[1;36mSandbox Management:\033[0m"
13- @printf " %-28s - %s\n" " make sandbox" " Create sandbox for features"
14- @printf " %-28s - %s\n" " make clean" " Remove sandbox"
16+ @echo " Available make commands"
17+ @echo " ------------------------"
18+ @echo " Sandbox Management:"
19+ @printf " %-28s %s\n" " make sandbox" " Create sandbox using Copier and answers file"
20+ @printf " %-28s %s\n" " make interactive" " Prompt user to create .copier-answers.yml"
21+ @printf " %-28s %s\n" " make clean" " Remove the generated sandbox directory"
1522 @echo " "
16- @echo " \033[1;36mDevcontainer Lifecycle:\033[0m"
17- @printf " %-28s - %s\n" " make devcontainer-up" " Build/start devcontainer"
18- @printf " %-28s - %s\n" " make build" " Build the container only (no attach)"
19- @printf " %-28s - %s\n" " make up" " Start/attach to running container"
20- @printf " %-28s - %s\n" " make rebuild" " Clean + re-sandbox + up"
21- @printf " %-28s - %s\n" " make stop" " Stop the devcontainer"
22- @printf " %-28s - %s\n" " make logs" " Show container logs"
23+ @echo " Devcontainer Lifecycle:"
24+ @printf " %-28s %s\n" " make devcontainer-up" " Create and run devcontainer"
25+ @printf " %-28s %s\n" " make build" " Build devcontainer image only"
26+ @printf " %-28s %s\n" " make up" " Alias to 'devcontainer-up'"
27+ @printf " %-28s %s\n" " make exec CMD='zsh'" " Execute command in container"
2328 @echo " "
24- @echo " \033[1;36mDevcontainer Utilities:\033[0m "
25- @printf " %-28s - %s\n" " make exec CMD= \" zsh \" " " Execute a command in the devcontainer "
26- @printf " %-28s - %s\n" " make interactive " " Interactive feature/image selection "
29+ @echo " Utility and Maintenance: "
30+ @printf " %-28s %s\n" " make format " " Format devcontainer.json using jq "
31+ @printf " %-28s %s\n" " make container-id " " Print running devcontainer ID "
2732 @echo " "
28- @echo " \033[1;36mUsage Examples:\033[0m"
29- @echo " --------------------------------------"
30- @echo " make sandbox FEATURES=\" shell hello\" IMAGE=<image>"
31- @echo " make devcontainer-up FEATURES=\" shell hello\" IMAGE=<image>"
33+ @echo " Reference:"
34+ @echo " - Features live under ./src/<feature>"
35+ @echo " - Base images: $( IMAGES) "
3236 @echo " "
37+ @echo " Examples:"
38+ @echo " make sandbox FEATURES=\" shell hello\" IMAGE=debian:latest"
39+ @echo " make devcontainer-up"
3340
41+ # List available feature folders
3442list-features :
3543 @echo " Available features:"
3644 @cd src && find . -maxdepth 1 -mindepth 1 -type d | sed ' s|^\./||' | sort | nl
3745
46+ # List supported base images
3847list-images :
3948 @echo " Available base images:"
4049 @echo " $( IMAGES) " | tr ' ' ' \n' | sort | nl
4150
42- sandbox :
43- @echo " Creating sandbox environment for features: $( FEATURES) with base image: $( IMAGE) "
51+ # Ensure Copier is installed in a local virtualenv
52+ ensure-copier :
53+ @echo " Checking for Copier..."
54+ @if [ ! -x " $( COPIER_BIN) " ]; then \
55+ echo " Copier not found. Creating virtualenv..." ; \
56+ if ! command -v python3 > /dev/null 2>&1 ; then \
57+ echo " python3 is required but not found. Please install it." ; \
58+ exit 1; \
59+ fi ; \
60+ python3 -m venv $(COPIER_VENV ) ; \
61+ . $(COPIER_VENV ) /bin/activate && pip install --upgrade pip copier; \
62+ echo " Copier installed in $( COPIER_VENV) " ; \
63+ else \
64+ echo " Copier already available." ; \
65+ fi
66+
67+ # Generate the sandbox with Copier
68+ sandbox : ensure-copier
69+ @if [ ! -f $( ANSWERS_FILE) ]; then \
70+ echo " No $( ANSWERS_FILE) found. Running interactive setup..." ; \
71+ $(MAKE ) interactive; \
72+ else \
73+ read -p " Use existing $( ANSWERS_FILE) ? [Y/n]: " CONFIRM; \
74+ if [ " $$ CONFIRM" = " n" ] || [ " $$ CONFIRM" = " N" ]; then \
75+ $(MAKE ) interactive; \
76+ fi ; \
77+ fi
78+ @echo " Using $( ANSWERS_FILE) to generate sandbox..."
4479 rm -rf $(SANDBOX_DIR )
80+ mkdir -p $(SANDBOX_DIR )
81+ @echo " Copying feature definitions into sandbox..."
4582 mkdir -p $(SANDBOX_DIR ) /.devcontainer/features
46- @for feature in $(FEATURES ) ; do \
47- cp -r src/$$ feature $(SANDBOX_DIR ) /.devcontainer/features/$$ feature; \
48- done
49- @echo ' {' > $(SANDBOX_DIR ) /.devcontainer/devcontainer.json
50- @echo ' "name": "Feature Test Sandbox",' >> $(SANDBOX_DIR ) /.devcontainer/devcontainer.json
51- @echo ' "image": "$(IMAGE)",' >> $(SANDBOX_DIR ) /.devcontainer/devcontainer.json
52- @echo ' "features": {' >> $(SANDBOX_DIR ) /.devcontainer/devcontainer.json
53- @features_array=$(FEATURES ) ; \
54- for feature in $$ features_array; do \
55- echo " \" ./features/$$ feature\" : {}," >> $(SANDBOX_DIR ) /.devcontainer/devcontainer.json; \
56- done
57- sed -i ' ' ' $$s/,$$//' $(SANDBOX_DIR ) /.devcontainer/devcontainer.json
58- @echo ' }' >> $(SANDBOX_DIR ) /.devcontainer/devcontainer.json
59- @echo ' }' >> $(SANDBOX_DIR ) /.devcontainer/devcontainer.json
60- @echo " Sandbox created at $( SANDBOX_DIR) /"
83+ cp -R src/* $(SANDBOX_DIR ) /.devcontainer/features/
84+ cp $(ANSWERS_FILE ) $(SANDBOX_ANSWERS_FILE )
85+ $(COPIER_BIN ) copy -a $(notdir $(SANDBOX_ANSWERS_FILE ) ) .template $(SANDBOX_DIR )
86+ @$(MAKE ) format
87+ @jq . $(SANDBOX_DIR ) /.devcontainer/devcontainer.json
88+
89+
90+ # Prompt user to select features and base image, then generate answers file
91+ interactive : ensure-copier
92+ @$(MAKE ) list-features
93+ @read -p " Select feature numbers (space-separated): " NUMS; \
94+ FEATURES_SELECTED=" " ; \
95+ for n in $$ NUMS; do \
96+ F=$$(cd src && find . -maxdepth 1 -mindepth 1 -type d | sed 's|^\./||' | sort | sed -n "$${n}p" ) ; \
97+ FEATURES_SELECTED=" $$ FEATURES_SELECTED $$ F" ; \
98+ done ; \
99+ echo " " ; \
100+ $(MAKE ) list-images; \
101+ read -p " Select image number: " IMG_NUM; \
102+ IMAGE_SELECTED=$$(echo "$(IMAGES ) " | tr ' ' '\n' | sort | sed -n "$${IMG_NUM}p" ) ; \
103+ echo " " ; \
104+ echo " You selected: $$ FEATURES_SELECTED for image $$ IMAGE_SELECTED" ; \
105+ echo " features:" > $(ANSWERS_FILE ) ; \
106+ for f in $$ FEATURES_SELECTED; do echo " - $$ f" ; done >> $(ANSWERS_FILE ) ; \
107+ echo " image: $$ IMAGE_SELECTED" >> $(ANSWERS_FILE ) ; \
108+ echo " $( ANSWERS_FILE) generated."
61109
110+ # Clean the sandbox directory
62111clean :
63112 @echo " Cleaning sandbox..."
64113 rm -rf $(SANDBOX_DIR )
65114 @echo " Sandbox cleaned."
66115
116+ # Devcontainer lifecycle commands
117+
67118devcontainer-up : sandbox
68- @echo " Launching devcontainer for features $( FEATURES ) using image $( IMAGE ) ..."
119+ @echo " Launching devcontainer..."
69120 cd $(SANDBOX_DIR ) && devcontainer up --workspace-folder .
70121
71122build :
@@ -74,30 +125,15 @@ build:
74125up :
75126 cd $(SANDBOX_DIR ) && devcontainer up --workspace-folder .
76127
77- rebuild : clean devcontainer-up
78-
79128exec :
80129 cd $(SANDBOX_DIR ) && devcontainer exec --workspace-folder . -- $(CMD )
81130
82- stop :
83- cd $(SANDBOX_DIR ) && devcontainer stop --workspace-folder .
84-
85- logs :
86- cd $(SANDBOX_DIR ) && devcontainer logs --workspace-folder .
131+ # Format devcontainer.json using jq
132+ format :
133+ @echo " Formatting devcontainer.json..."
134+ @jq . $(SANDBOX_DIR ) /.devcontainer/devcontainer.json > $(SANDBOX_DIR ) /.devcontainer/devcontainer.json.tmp && \
135+ mv $(SANDBOX_DIR ) /.devcontainer/devcontainer.json.tmp $(SANDBOX_DIR ) /.devcontainer/devcontainer.json && \
136+ echo " Formatted successfully."
87137
88- interactive :
89- @$(MAKE ) list-features
90- @read -p " Select feature numbers (space-separated): " FEATURES_NUMBERS; \
91- FEATURES_SELECTED=" " ; \
92- for num in $$ FEATURES_NUMBERS; do \
93- FEATURE=$$(cd src && find . -maxdepth 1 -mindepth 1 -type d | sed 's|^\./||' | sort | sed -n "$${num}p" ) ; \
94- FEATURES_SELECTED=" $$ FEATURES_SELECTED $$ FEATURE" ; \
95- done ; \
96- echo " " ; \
97- $(MAKE ) list-images; \
98- read -p " Select image number: " IMAGE_NUMBER; \
99- IMAGE_SELECTED=$$(echo "$(IMAGES ) " | tr ' ' '\n' | sort | sed -n "$${IMAGE_NUMBER}p" ) ; \
100- echo " " ; \
101- echo " Using features: $$ FEATURES_SELECTED" ; \
102- echo " Using image: $$ IMAGE_SELECTED" ; \
103- $(MAKE ) devcontainer-up FEATURES=" $$ FEATURES_SELECTED" IMAGE=" $$ IMAGE_SELECTED"
138+ container-id :
139+ @docker ps --filter " name=devcontainer" --format " {{.ID}}"
0 commit comments