-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
240 lines (208 loc) · 9.23 KB
/
Makefile
File metadata and controls
240 lines (208 loc) · 9.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
.PHONY: help clean tangle scheme hy test lint format doc run-scheme run-hy install tmux-start tmux-attach tmux-stop tmux-status emacs-repl
# Default target is help
.DEFAULT_GOAL := help
# Directories
SCHEME_DIR := scheme
HY_DIR := hy
TEST_DIR := tests
ORG_FILES := $(wildcard *.org)
SCHEME_SOURCES := $(wildcard $(SCHEME_DIR)/**/*.scm)
HY_SOURCES := $(wildcard $(HY_DIR)/**/*.hy)
# Project configuration
PROJECT_NAME := functional-data-structures
PROJECT_ROOT := $(shell pwd)
EMACS_CONFIG := $(PROJECT_ROOT)/$(PROJECT_NAME).el
TMUX_SESSION := $(PROJECT_NAME)
# Commands
GUILE := guile
HY := hy
EMACS := emacs -Q --batch
GUILD := guild
HY_FORMATTER := black
GUILEC := guild compile
# Color definitions
CYAN := \033[36m
GREEN := \033[32m
YELLOW := \033[33m
RESET := \033[0m
# Simple help command
help: ## Show this help message
@echo "$(GREEN)Functional Data Structures - Makefile Help$(RESET)"
@echo "$(YELLOW)Usage:$(RESET) make [target]"
@echo ""
@echo "$(YELLOW)Available targets:$(RESET)"
@echo " $(CYAN)all$(RESET) Tangle code, run tests, and lint"
@echo " $(CYAN)clean$(RESET) Remove generated and temporary files"
@echo " $(CYAN)tangle$(RESET) Tangle source code from org files"
@echo " $(CYAN)detangle$(RESET) Update org files with changes from source (reverse tangle)"
@echo " $(CYAN)compile-scheme$(RESET) Compile Scheme files"
@echo " $(CYAN)install$(RESET) Install Python dependencies"
@echo " $(CYAN)shell$(RESET) Activate Poetry shell"
@echo " $(CYAN)test$(RESET) Run all tests"
@echo " $(CYAN)test-scheme$(RESET) Run Scheme tests"
@echo " $(CYAN)test-hy$(RESET) Run Hy tests"
@echo " $(CYAN)lint$(RESET) Run linters for both Scheme and Hy"
@echo " $(CYAN)format$(RESET) Format both Scheme and Hy code"
@echo " $(CYAN)doc$(RESET) Generate documentation"
@echo " $(CYAN)run-scheme$(RESET) Run Scheme implementation"
@echo " $(CYAN)run-hy$(RESET) Run Hy implementation"
@echo " $(CYAN)get-paper$(RESET) Download Okasaki's thesis paper"
@echo ""
@echo "$(YELLOW)Development environment:$(RESET)"
@echo " $(CYAN)tmux-start$(RESET) Start tmux session with Emacs"
@echo " $(CYAN)tmux-attach$(RESET) Attach to existing tmux session"
@echo " $(CYAN)tmux-stop$(RESET) Stop tmux session"
@echo " $(CYAN)tmux-status$(RESET) Show tmux session status"
@echo " $(CYAN)emacs-repl$(RESET) Start Emacs with Geiser REPL"
all: tangle test lint ## Tangle code, run tests, and lint
clean: ## Remove generated and temporary files
@echo "$(CYAN)Cleaning generated files...$(RESET)"
@if [ -f scheme/.generated ]; then \
echo "Removing generated Scheme files..."; \
rm -rf $(SCHEME_DIR); \
else \
echo "Cleaning Scheme compiled files..."; \
rm -rf $(SCHEME_DIR)/**/*.go; \
fi
@if [ -f hy/.generated ]; then \
echo "Removing generated Hy files..."; \
rm -rf $(HY_DIR); \
else \
echo "Cleaning Hy cache files..."; \
rm -rf $(HY_DIR)/**/__pycache__; \
fi
@rm -rf __pycache__
@rm -rf .pytest_cache
@rm -rf dist
@rm -rf build
@rm -rf *.egg-info
@find . -name "*~" -delete
@find . -name "*.pyc" -delete
@find . -name "__pycache__" -delete
@echo "$(GREEN)Done cleaning$(RESET)"
# Code generation
tangle: ## Tangle source code from org files
@echo "$(CYAN)Tangling Org files...$(RESET)"
@for file in $(ORG_FILES); do \
echo "Tangling $$file..."; \
$(EMACS) --eval "(require 'org)" --eval "(org-babel-tangle-file \"$$file\")"; \
done
@echo "$(GREEN)Done tangling files to scheme/ and hy/ (marked as generated)$(RESET)"
@touch scheme/.generated
@touch hy/.generated
detangle: ## Update org files from source code (reverse of tangle)
@echo "$(CYAN)Detangling source files...$(RESET)"
@for file in $(ORG_FILES); do \
echo "Processing $$file..."; \
$(EMACS) --eval "(require 'org)" --eval "(org-babel-detangle \"$$file\")"; \
done
@echo "$(GREEN)Done detangling$(RESET)"
# Build targets
compile-scheme: tangle ## Compile Scheme files
@echo "Compiling Scheme files..."
@for file in $(SCHEME_SOURCES); do \
echo "Compiling $$file..."; \
$(GUILEC) -o $$file.go $$file; \
done
@echo "Done compiling Scheme files"
install: ## Install Python dependencies and activate environment
@echo "Installing Python dependencies..."
@poetry install --with dev
@echo "Done installing dependencies"
shell: ## Activate Poetry shell
@echo "Activating Poetry shell..."
@poetry shell
# Test targets
test: test-scheme test-hy ## Run all tests
test-scheme: tangle ## Run Scheme tests
@echo "$(CYAN)Running Scheme tests...$(RESET)"
@GUILE_LOAD_PATH="./scheme:$$GUILE_LOAD_PATH" $(GUILE) -L . -e main $(TEST_DIR)/scheme/test-runner.scm || (echo "$(RED)Scheme tests failed$(RESET)"; exit 1)
@echo "$(GREEN)Scheme tests passed$(RESET)"
test-hy: tangle ## Run Hy tests
@echo "$(CYAN)Running Hy tests...$(RESET)"
@PYTHONPATH="./hy:$$PYTHONPATH" poetry run pytest $(TEST_DIR)/hy || (echo "$(RED)Hy tests failed$(RESET)"; exit 1)
@echo "$(GREEN)Hy tests passed$(RESET)"
# Lint and format
lint: lint-scheme lint-hy ## Run linters for both Scheme and Hy
lint-scheme: ## Lint Scheme code
@echo "Linting Scheme code..."
@if command -v $(GUILD) >/dev/null 2>&1; then \
$(GUILD) lint $(SCHEME_SOURCES) || (echo "Scheme linting failed"; exit 1); \
else \
echo "Guild lint not available. Skipping Scheme linting."; \
fi
@echo "Scheme linting passed"
lint-hy: ## Lint Hy code
@echo "Linting Hy code..."
@poetry run ruff check $(HY_DIR) || (echo "Hy linting failed"; exit 1)
@echo "Hy linting passed"
format: format-scheme format-hy ## Format both Scheme and Hy code
format-scheme: ## Format Scheme code
@echo "Formatting Scheme code..."
@echo "Note: Automatic formatting for Scheme is not available."
@echo "Please format Scheme code manually."
format-hy: ## Format Hy code
@echo "Formatting Hy code..."
@$(HY_FORMATTER) $(HY_DIR)
@echo "Hy code formatted"
# Documentation
doc: ## Generate documentation
@echo "Generating documentation..."
@$(EMACS) --eval "(require 'org)" --eval "(require 'ox-html)" \
--eval "(dolist (file '($(ORG_FILES))) (with-current-buffer (find-file file) (org-html-export-to-html)))"
@echo "Documentation generated"
# Run targets
run-scheme: tangle ## Run Scheme implementation
@echo "Running Scheme implementation..."
@GUILE_LOAD_PATH="./scheme:$$GUILE_LOAD_PATH" $(GUILE) -c "(use-modules (okasaki stack)) (display \"Stack module loaded successfully\n\")"
run-hy: tangle ## Run Hy implementation
@echo "Running Hy implementation..."
@PYTHONPATH="./hy:$$PYTHONPATH" $(HY) -c "(import okasaki.stack) (print \"Hy stack module loaded successfully\")"
# Git and contribution helpers
commit-conventional: ## Create a conventional commit (usage: make commit-conventional msg="type(scope): message")
@if [ -z "$(msg)" ]; then \
echo "Error: Missing commit message."; \
echo "Usage: make commit-conventional msg=\"type(scope): message\""; \
echo "Example: make commit-conventional msg=\"feat(queue): add persistent queue implementation\""; \
exit 1; \
fi
@echo "Creating conventional commit..."
@git commit -m "$(msg)" --trailer "Signed-off-by: $$(git config user.name) <$$(git config user.email)>"
@echo "Commit created"
get-paper: ## Download Okasaki's thesis paper
@echo "Downloading Okasaki's thesis paper..."
@mkdir -p references
@curl -L https://www.cs.cmu.edu/~rwh/students/okasaki.pdf -o references/okasaki-thesis.pdf
@echo "$(GREEN)Paper downloaded to references/okasaki-thesis.pdf$(RESET)"
# Tmux and Emacs development environment
tmux-start: ## Start tmux session with project-specific Emacs configuration
@echo "$(CYAN)Starting tmux session '$(TMUX_SESSION)' with Emacs...$(RESET)"
@if tmux has-session -t $(TMUX_SESSION) 2>/dev/null; then \
echo "Session '$(TMUX_SESSION)' already exists. Attaching..."; \
tmux attach-session -t $(TMUX_SESSION); \
else \
echo "Creating new session '$(TMUX_SESSION)'..."; \
tmux new-session -d -s $(TMUX_SESSION) "emacs -nw -l $(EMACS_CONFIG)"; \
echo "Session created. Getting TTY..."; \
tmux list-panes -t $(TMUX_SESSION) -F "Pane TTY: #{pane_tty}"; \
echo "$(GREEN)Session '$(TMUX_SESSION)' started$(RESET)"; \
echo "Attach with: tmux attach-session -t $(TMUX_SESSION)"; \
fi
tmux-attach: ## Attach to existing tmux session
@echo "$(CYAN)Attaching to tmux session '$(TMUX_SESSION)'...$(RESET)"
@tmux attach-session -t $(TMUX_SESSION) || echo "$(YELLOW)No session found. Run 'make tmux-start' first.$(RESET)"
tmux-stop: ## Stop tmux session
@echo "$(CYAN)Stopping tmux session '$(TMUX_SESSION)'...$(RESET)"
@tmux kill-session -t $(TMUX_SESSION) 2>/dev/null || echo "$(YELLOW)Session '$(TMUX_SESSION)' not found$(RESET)"
@echo "$(GREEN)Session stopped$(RESET)"
tmux-status: ## Show tmux session status
@echo "$(CYAN)Tmux session status:$(RESET)"
@if tmux has-session -t $(TMUX_SESSION) 2>/dev/null; then \
echo "$(GREEN)Session '$(TMUX_SESSION)' is running$(RESET)"; \
tmux list-panes -t $(TMUX_SESSION) -F " Pane: #{pane_index} TTY: #{pane_tty} Size: #{pane_width}x#{pane_height}"; \
else \
echo "$(YELLOW)Session '$(TMUX_SESSION)' is not running$(RESET)"; \
fi
emacs-repl: ## Start Emacs with Geiser REPL for Scheme development
@echo "$(CYAN)Starting Emacs with Geiser REPL...$(RESET)"
@emacs -l $(EMACS_CONFIG) --eval "(fds-open-repl)"