forked from Nachtzuster/BirdNET-Pi
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
274 lines (220 loc) · 8.7 KB
/
Makefile
File metadata and controls
274 lines (220 loc) · 8.7 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
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
# BirdNET-Pi Makefile
.PHONY: all build test test-verbose test-coverage test-race lint clean help
.PHONY: dev-server dev-web install-deps generate
.PHONY: build-arm64 build-arm build-pi build-all-platforms
.PHONY: build-recording build-recording-arm64
.PHONY: check-prereqs install
# Go parameters
GOCMD=go
GOBUILD=$(GOCMD) build
GOTEST=$(GOCMD) test
GOGET=$(GOCMD) get
GOMOD=$(GOCMD) mod
GOFMT=gofmt
BINARY_NAME=birdnet-server
BINARY_DIR=bin
# Build flags
BUILD_FLAGS=-ldflags="-s -w"
# Test flags
TEST_FLAGS=-v
COVERAGE_FLAGS=-coverprofile=coverage.out -covermode=atomic
# Directories
CMD_DIR=./cmd/server
CMD_RECORDING_DIR=./cmd/birdnet-recording
RECORDING_BINARY_NAME=birdnet-recording
INTERNAL_DIR=./internal/...
WEB_DIR=./web
all: test build
## Build targets
build: ## Build the server binary
@echo "Building $(BINARY_NAME)..."
@mkdir -p $(BINARY_DIR)
$(GOBUILD) $(BUILD_FLAGS) -o $(BINARY_DIR)/$(BINARY_NAME) $(CMD_DIR)
build-debug: ## Build with debug symbols
@echo "Building $(BINARY_NAME) (debug)..."
@mkdir -p $(BINARY_DIR)
$(GOBUILD) -o $(BINARY_DIR)/$(BINARY_NAME) $(CMD_DIR)
build-arm64: ## Build for Raspberry Pi 3/4/5 (64-bit ARM)
@echo "Building $(BINARY_NAME) for linux/arm64..."
@mkdir -p $(BINARY_DIR)
GOOS=linux GOARCH=arm64 $(GOBUILD) $(BUILD_FLAGS) -o $(BINARY_DIR)/$(BINARY_NAME)-linux-arm64 $(CMD_DIR)
build-arm: ## Build for Raspberry Pi Zero/older Pi (32-bit ARM)
@echo "Building $(BINARY_NAME) for linux/arm..."
@mkdir -p $(BINARY_DIR)
GOOS=linux GOARCH=arm GOARM=7 $(GOBUILD) $(BUILD_FLAGS) -o $(BINARY_DIR)/$(BINARY_NAME)-linux-arm $(CMD_DIR)
build-recording: ## Build the recording binary
@echo "Building $(RECORDING_BINARY_NAME)..."
@mkdir -p $(BINARY_DIR)
$(GOBUILD) $(BUILD_FLAGS) -o $(BINARY_DIR)/$(RECORDING_BINARY_NAME) $(CMD_RECORDING_DIR)
build-recording-arm64: ## Build recording binary for Raspberry Pi (64-bit ARM)
@echo "Building $(RECORDING_BINARY_NAME) for linux/arm64..."
@mkdir -p $(BINARY_DIR)
GOOS=linux GOARCH=arm64 $(GOBUILD) $(BUILD_FLAGS) -o $(BINARY_DIR)/$(RECORDING_BINARY_NAME)-linux-arm64 $(CMD_RECORDING_DIR)
build-pi: build-arm64 ## Alias for build-arm64 (most common Pi target)
@echo "Pi build complete: $(BINARY_DIR)/$(BINARY_NAME)-linux-arm64"
build-all-platforms: build build-arm64 build-arm build-recording build-recording-arm64 ## Build for all platforms
@echo "All platform builds complete:"
@ls -la $(BINARY_DIR)/
## Test targets
test: ## Run all tests
@echo "Running tests..."
$(GOTEST) $(INTERNAL_DIR)
test-verbose: ## Run tests with verbose output
@echo "Running tests (verbose)..."
$(GOTEST) $(TEST_FLAGS) $(INTERNAL_DIR)
test-coverage: ## Run tests with coverage report
@echo "Running tests with coverage..."
$(GOTEST) $(COVERAGE_FLAGS) $(INTERNAL_DIR)
@echo "Coverage report generated: coverage.out"
@$(GOCMD) tool cover -func=coverage.out
test-coverage-html: test-coverage ## Generate HTML coverage report
@echo "Generating HTML coverage report..."
$(GOCMD) tool cover -html=coverage.out -o coverage.html
@echo "Coverage report: coverage.html"
test-race: ## Run tests with race detector
@echo "Running tests with race detector..."
$(GOTEST) -race $(INTERNAL_DIR)
test-short: ## Run only short tests
@echo "Running short tests..."
$(GOTEST) -short $(INTERNAL_DIR)
test-db: ## Run database tests only
@echo "Running database tests..."
$(GOTEST) $(TEST_FLAGS) ./internal/db/...
test-ws: ## Run WebSocket tests only
@echo "Running WebSocket tests..."
$(GOTEST) $(TEST_FLAGS) ./internal/ws/...
test-api: ## Run API handler tests only
@echo "Running API tests..."
$(GOTEST) $(TEST_FLAGS) ./internal/api/...
test-mlclient: ## Run ML client tests only
@echo "Running ML client tests..."
$(GOTEST) $(TEST_FLAGS) ./internal/mlclient/...
test-monitor: ## Run monitor tests only
@echo "Running monitor tests..."
$(GOTEST) $(TEST_FLAGS) ./internal/monitor/...
benchmark: ## Run benchmarks
@echo "Running benchmarks..."
$(GOTEST) -bench=. -benchmem $(INTERNAL_DIR)
## Code quality
lint: ## Run linters
@echo "Running linters..."
@if command -v golangci-lint >/dev/null 2>&1; then \
golangci-lint run ./...; \
else \
echo "golangci-lint not installed. Install with:"; \
echo " go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest"; \
fi
fmt: ## Format Go code
@echo "Formatting code..."
$(GOFMT) -s -w .
fmt-check: ## Check if code is formatted
@echo "Checking code format..."
@test -z "$$($(GOFMT) -l .)" || (echo "Code not formatted. Run 'make fmt'" && exit 1)
vet: ## Run go vet
@echo "Running go vet..."
$(GOCMD) vet $(INTERNAL_DIR)
## Setup
check-prereqs: ## Verify required tools are installed with minimum versions
@echo "Checking prerequisites..."
@command -v go >/dev/null 2>&1 || { echo "ERROR: go is not installed (need 1.21+)"; exit 1; }
@command -v node >/dev/null 2>&1 || { echo "ERROR: node is not installed (need 18+)"; exit 1; }
@command -v npm >/dev/null 2>&1 || { echo "ERROR: npm is not installed"; exit 1; }
@command -v python3 >/dev/null 2>&1 || { echo "ERROR: python3 is not installed (need 3.9+)"; exit 1; }
@GO_VER=$$(go version | grep -oP 'go(\d+)\.(\d+)' | grep -oP '\d+$$'); \
GO_MAJOR=$$(go version | grep -oP 'go\d+' | grep -oP '\d+'); \
if [ "$$GO_MAJOR" -lt 1 ] || { [ "$$GO_MAJOR" -eq 1 ] && [ "$$GO_VER" -lt 21 ]; }; then \
echo "ERROR: Go 1.21+ required, found $$(go version)"; exit 1; \
fi
@NODE_MAJOR=$$(node --version | grep -oP '\d+' | head -1); \
if [ "$$NODE_MAJOR" -lt 18 ]; then \
echo "ERROR: Node 18+ required, found $$(node --version)"; exit 1; \
fi
@PY_VER=$$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")'); \
PY_MAJOR=$$(echo $$PY_VER | cut -d. -f1); \
PY_MINOR=$$(echo $$PY_VER | cut -d. -f2); \
if [ "$$PY_MAJOR" -lt 3 ] || { [ "$$PY_MAJOR" -eq 3 ] && [ "$$PY_MINOR" -lt 9 ]; }; then \
echo "ERROR: Python 3.9+ required, found $$PY_VER"; exit 1; \
fi
@echo "All prerequisites satisfied."
install: check-prereqs ## Full developer setup: check prereqs, install deps, build all
@echo "Installing dependencies and building..."
$(GOMOD) download
cd $(WEB_DIR) && npm install
@$(MAKE) build
@$(MAKE) build-recording
@$(MAKE) build-web
@echo "Install complete. Run 'make test' to verify."
## Dependencies
install-deps: ## Install Go dependencies
@echo "Installing Go dependencies..."
$(GOMOD) download
$(GOMOD) tidy
install-tools: ## Install development tools
@echo "Installing development tools..."
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest
go install -tags 'sqlite3' github.com/golang-migrate/migrate/v4/cmd/migrate@latest
## Code generation
generate: ## Generate sqlc code
@echo "Generating sqlc code..."
@if command -v sqlc >/dev/null 2>&1; then \
cd internal/db && sqlc generate; \
else \
echo "sqlc not installed. Install with: go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest"; \
fi
## Database migrations
migrate-up: ## Run database migrations
@echo "Running migrations..."
@if command -v migrate >/dev/null 2>&1; then \
migrate -database "sqlite3://$(DB_PATH)" -path migrations up; \
else \
echo "migrate not installed. Install with:"; \
echo " go install -tags 'sqlite3' github.com/golang-migrate/migrate/v4/cmd/migrate@latest"; \
fi
migrate-down: ## Rollback last migration
@echo "Rolling back migration..."
@if command -v migrate >/dev/null 2>&1; then \
migrate -database "sqlite3://$(DB_PATH)" -path migrations down 1; \
else \
echo "migrate not installed"; \
fi
migrate-create: ## Create new migration (usage: make migrate-create NAME=migration_name)
@echo "Creating migration: $(NAME)"
@if command -v migrate >/dev/null 2>&1; then \
migrate create -ext sql -dir migrations -seq $(NAME); \
else \
echo "migrate not installed"; \
fi
## Development
dev-server: ## Run development server with hot reload
@echo "Starting development server..."
@if command -v air >/dev/null 2>&1; then \
air; \
else \
echo "air not installed. Running without hot reload..."; \
$(GOCMD) run $(CMD_DIR); \
fi
dev-web: ## Run web development server
@echo "Starting web development server..."
cd $(WEB_DIR) && npm run dev
install-web: ## Install web dependencies
@echo "Installing web dependencies..."
cd $(WEB_DIR) && npm install
build-web: ## Build web assets
@echo "Building web assets..."
cd $(WEB_DIR) && npm run build
## Cleanup
clean: ## Remove build artifacts
@echo "Cleaning..."
rm -rf $(BINARY_DIR)
rm -f coverage.out coverage.html
rm -rf $(WEB_DIR)/dist
rm -rf $(WEB_DIR)/node_modules
## Help
help: ## Show this help
@echo "BirdNET-Pi Makefile"
@echo ""
@echo "Usage: make [target]"
@echo ""
@echo "Targets:"
@grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-20s\033[0m %s\n", $$1, $$2}'