-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
336 lines (306 loc) · 15.9 KB
/
Makefile
File metadata and controls
336 lines (306 loc) · 15.9 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
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
.PHONY: all coverage linux macos windows android clean test analyze setup-linux setup-macos setup-windows mix icons \
install install-linux uninstall precommit help check release icons-check deps test-cli run-gui rebuild
.DEFAULT_GOAL := help
# Paths
LINUX_BUNDLE = build/linux/x64/release/bundle
MACOS_BUNDLE = build/macos/Build/Products/Release/crossbar.app/Contents/MacOS
WINDOWS_BUNDLE = build/windows/x64/runner/Release
# Detect OS and set default target
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin)
DEFAULT_TARGET = macos
else ifneq (,$(findstring MINGW,$(UNAME_S)))
DEFAULT_TARGET = windows
else ifneq (,$(findstring CYGWIN,$(UNAME_S)))
DEFAULT_TARGET = windows
else ifeq ($(OS),Windows_NT)
DEFAULT_TARGET = windows
else
DEFAULT_TARGET = linux
endif
# TTY detection: suppress verbose output in non-interactive mode (CI/agents)
ifneq ($(shell test -t 1 && echo yes),yes)
LOG = /tmp/crossbar-make.log
QUIET = > $(LOG) 2>&1 || (cat $(LOG) && exit 1)
else
LOG = /dev/null
QUIET =
endif
# Analyzer budget: maximum number of info+warning issues allowed
ANALYZE_BUDGET ?= 100
help: ## Show this help
@echo "Usage: make [target]"
@echo ""
@echo "Targets:"
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " \033[36m%-20s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
all: $(DEFAULT_TARGET) ## Build for detected OS (alias for linux/macos/windows)
@echo "Building for detected OS: $(DEFAULT_TARGET)"
check: ## Quick validation (analyze + test, no builds)
@echo "══════════════════════════════════════════════════════════════"
@echo " QUICK CHECK"
@echo "══════════════════════════════════════════════════════════════"
@echo ""
@echo "Step 1/2: Static Analysis (budget: $(ANALYZE_BUDGET))"
@echo "──────────────────────────────────────────────────────────────"
$(MAKE) analyze
@echo ""
@echo "Step 2/2: Tests"
@echo "──────────────────────────────────────────────────────────────"
$(MAKE) test
@echo ""
@echo "══════════════════════════════════════════════════════════════"
@echo " CHECK PASSED"
@echo "══════════════════════════════════════════════════════════════"
precommit: ## Run full pre-commit sequence (analyze, coverage, linux, android)
@echo "══════════════════════════════════════════════════════════════"
@echo " PRECOMMIT VERIFICATION (AGENTS.md)"
@echo "══════════════════════════════════════════════════════════════"
@echo ""
@echo "Step 1/4: Static Analysis (budget: $(ANALYZE_BUDGET))"
@echo "──────────────────────────────────────────────────────────────"
$(MAKE) analyze
@echo ""
@echo "Step 2/4: Tests with Coverage (target: 35-60%)"
@echo "──────────────────────────────────────────────────────────────"
$(MAKE) coverage
@echo ""
@echo "Step 3/4: Linux Build"
@echo "──────────────────────────────────────────────────────────────"
$(MAKE) linux
@echo ""
@echo "Step 4/4: Android Build"
@echo "──────────────────────────────────────────────────────────────"
$(MAKE) android
@echo ""
@echo "══════════════════════════════════════════════════════════════"
@echo " PRECOMMIT PASSED - Safe to commit!"
@echo "══════════════════════════════════════════════════════════════"
linux: ## Build for Linux (Flutter GUI + CLI + Tray Daemon)
@echo "Building Flutter GUI..."
flutter build linux --release $(QUIET)
@echo "Setting up unified architecture..."
mv $(LINUX_BUNDLE)/crossbar $(LINUX_BUNDLE)/crossbar-gui
@echo "Compiling unified CLI from packages/crossbar_cli..."
cd packages/crossbar_cli && dart compile exe bin/crossbar.dart -o ../../$(LINUX_BUNDLE)/crossbar $(QUIET)
@echo "Compiling tray daemon for multi-icon support..."
dart build cli --target=bin/crossbar_tray_daemon.dart --output=build/tray_daemon_tmp $(QUIET)
cp build/tray_daemon_tmp/bundle/bin/crossbar_tray_daemon $(LINUX_BUNDLE)/crossbar_tray_daemon
rm -rf build/tray_daemon_tmp
@echo "Copying desktop integration files..."
cp linux/com.verseles.crossbar.desktop $(LINUX_BUNDLE)/
cp assets/icons/icon_linux.png $(LINUX_BUNDLE)/crossbar.png
@echo "Done! Binaries at $(LINUX_BUNDLE)/"
@echo ""
@echo " crossbar - CLI + launcher (runs GUI if no args)"
@echo " crossbar-gui - Flutter GUI application"
@echo " crossbar_tray_daemon - Daemon for multi-icon tray support"
@echo ""
@ls -lh $(LINUX_BUNDLE)/crossbar*
install: install-linux ## Install Crossbar to ~/.local/ (Linux only)
install-linux: ## Run checks/builds and install Crossbar to ~/.local/ (Linux only)
@echo "Running checks and build before install..."
$(MAKE) analyze
$(MAKE) coverage
$(MAKE) linux
@echo "Installing Crossbar to $(INSTALL_DIR)..."
@mkdir -p $(INSTALL_DIR)/bin
@mkdir -p $(INSTALL_DIR)/share/crossbar
@mkdir -p $(INSTALL_DIR)/share/applications
@mkdir -p $(INSTALL_DIR)/share/icons/hicolor/128x128/apps
@mkdir -p $(INSTALL_DIR)/share/icons/hicolor/256x256/apps
@mkdir -p $(HOME)/.crossbar/plugins
@# Copy entire bundle
@cp -r $(LINUX_BUNDLE)/* $(INSTALL_DIR)/share/crossbar/
@# Create symlink in bin
@ln -sf $(INSTALL_DIR)/share/crossbar/crossbar $(INSTALL_DIR)/bin/crossbar
@# Install desktop file with correct paths
@# Note: Exec points to crossbar-gui directly, file named by APPLICATION_ID for GNOME matching
@sed 's|Icon=com.verseles.crossbar|Icon=$(INSTALL_DIR)/share/icons/hicolor/128x128/apps/com.verseles.crossbar.png|; s|Exec=.*|Exec=$(INSTALL_DIR)/share/crossbar/crossbar-gui|' \
linux/com.verseles.crossbar.desktop > $(INSTALL_DIR)/share/applications/com.verseles.crossbar.desktop
@# Install icons with APPLICATION_ID naming for proper GNOME association
@cp assets/icons/icon_linux.png $(INSTALL_DIR)/share/icons/hicolor/128x128/apps/com.verseles.crossbar.png
@cp assets/icons/icon_linux.png $(INSTALL_DIR)/share/icons/hicolor/256x256/apps/com.verseles.crossbar.png
@# Install symbolic icon for GNOME panel/notifications
@mkdir -p $(INSTALL_DIR)/share/icons/hicolor/symbolic/apps
@cp assets/icons/com.verseles.crossbar-symbolic.svg $(INSTALL_DIR)/share/icons/hicolor/symbolic/apps/
@# Update icon cache
@gtk-update-icon-cache $(INSTALL_DIR)/share/icons/hicolor 2>/dev/null || true
@echo ""
@echo "Crossbar installed successfully!"
@echo ""
@echo "Make sure $(INSTALL_DIR)/bin is in your PATH:"
@echo " export PATH=\"$$HOME/.local/bin:$$PATH\""
@echo ""
@echo "You can now run 'crossbar' from anywhere."
@echo "A desktop entry has been created - search for 'Crossbar' in your app menu."
INSTALL_DIR = $(HOME)/.local
uninstall: ## Uninstall Crossbar from ~/.local/
@echo "Uninstalling Crossbar..."
@rm -f $(INSTALL_DIR)/bin/crossbar
@rm -rf $(INSTALL_DIR)/share/crossbar
@rm -f $(INSTALL_DIR)/share/applications/crossbar.desktop
@rm -f $(INSTALL_DIR)/share/applications/com.verseles.crossbar.desktop
@rm -f $(INSTALL_DIR)/share/icons/hicolor/128x128/apps/crossbar.png
@rm -f $(INSTALL_DIR)/share/icons/hicolor/128x128/apps/com.verseles.crossbar.png
@rm -f $(INSTALL_DIR)/share/icons/hicolor/256x256/apps/crossbar.png
@rm -f $(INSTALL_DIR)/share/icons/hicolor/256x256/apps/com.verseles.crossbar.png
@rm -f $(INSTALL_DIR)/share/icons/hicolor/symbolic/apps/com.verseles.crossbar-symbolic.svg
@gtk-update-icon-cache $(INSTALL_DIR)/share/icons/hicolor 2>/dev/null || true
@echo "Crossbar uninstalled. User data in ~/.crossbar/ was preserved."
macos: ## Build for macOS (Flutter GUI + CLI)
@echo "Building Flutter GUI..."
flutter build macos --release $(QUIET)
@echo "Setting up unified architecture..."
mv $(MACOS_BUNDLE)/crossbar $(MACOS_BUNDLE)/crossbar-gui
@echo "Compiling unified CLI from packages/crossbar_cli..."
cd packages/crossbar_cli && dart compile exe bin/crossbar.dart -o ../../$(MACOS_BUNDLE)/crossbar $(QUIET)
@echo "Done! Binaries at $(MACOS_BUNDLE)/"
windows: ## Build for Windows (Flutter GUI + CLI)
@echo "Building Flutter GUI..."
flutter build windows --release $(QUIET)
@echo "Setting up unified architecture..."
mv $(WINDOWS_BUNDLE)/crossbar.exe $(WINDOWS_BUNDLE)/crossbar-gui.exe
@echo "Compiling unified CLI from packages/crossbar_cli..."
cd packages/crossbar_cli && dart compile exe bin/crossbar.dart -o ../../$(WINDOWS_BUNDLE)/crossbar.exe $(QUIET)
@echo "Done! Binaries at $(WINDOWS_BUNDLE)/"
CAPTION ?=
android: ## Build Android APK (and upload if configured)
flutter build apk --release --target-platform android-arm64 $(QUIET)
@VERSION=$$(grep '^version:' pubspec.yaml | cut -d' ' -f2); \
if [ -n "$(CAPTION)" ]; then \
~/bin/hey -f ./build/app/outputs/apk/release/crossbar.apk "<b>Crossbar v$$VERSION</b>\n\n$(CAPTION)"; \
else \
~/bin/hey -f ./build/app/outputs/apk/release/crossbar.apk "<b>Crossbar v$$VERSION</b>"; \
fi
@echo "Done! APK at build/app/outputs/apk/release/crossbar.apk"
test: ## Run unit/widget tests (excluding hardware)
flutter test --exclude-tags=hardware
coverage: ## Run tests with coverage report
flutter test --exclude-tags=hardware --coverage
@bash tool/ci/check_coverage.sh 35
analyze: ## Run static analysis (with budget gate)
@bash tool/ci/check_analyze_budget.sh $(ANALYZE_BUDGET)
clean: ## Clean build artifacts
flutter clean
rm -rf build/
deps: ## Get dependencies
flutter pub get
test-cli: ## Test CLI binary (requires linux build)
@echo "Testing CLI mode:"
$(LINUX_BUNDLE)/crossbar --cpu
@echo ""
@echo "Testing --version:"
$(LINUX_BUNDLE)/crossbar --version
run-gui: ## Run GUI (requires linux build)
$(LINUX_BUNDLE)/crossbar
rebuild: clean linux ## Clean and rebuild Linux
mix: ## Update repomix (if exists)
@if [ -f repomix-output.xml ]; then npx repomix --truncate-base64 --include-logs --top-files-len 20; fi
icons: ## Generate icons from assets
@echo "Generating tray icons..."
@cd assets/icons && \
magick icon.png -resize 48x48 -alpha extract mask.png && \
magick -size 48x48 xc:white mask.png -alpha off -compose CopyOpacity -composite PNG32:tray_icon_light.png && \
magick -size 48x48 xc:black mask.png -alpha off -compose CopyOpacity -composite PNG32:tray_icon_dark.png && \
magick -size 44x44 xc:black \( icon.png -resize 44x44 -alpha extract \) -alpha off -compose CopyOpacity -composite PNG32:tray_icon_macos.png && \
magick icon.png -resize 48x48 -define icon:auto-resize=48,32,16 tray_icon.ico && \
rm -f mask.png
@echo "Tray icons generated:"
@ls -la assets/icons/tray_icon*
@echo ""
@echo "Generating Linux icon with rounded corners (squircle style)..."
@cd assets/icons && \
magick icon_opaque.png -resize 256x256 \
\( +clone -alpha extract \
-draw "fill black polygon 0,0 0,48 48,0 fill white circle 48,48 48,0" \
\( +clone -flip \) -compose Multiply -composite \
\( +clone -flop \) -compose Multiply -composite \
\) -alpha off -compose CopyOpacity -composite PNG32:icon_linux.png
@echo "Linux icon generated:"
@ls -la assets/icons/icon_linux.png
@echo ""
@echo "Generating monochrome icon for Android Material You..."
@cd assets/icons && \
magick icon.png -resize 1024x1024 -alpha extract -negate PNG32:icon_monochrome.png
@echo "Monochrome icon generated:"
@ls -la assets/icons/icon_monochrome.png
@echo ""
@echo "Generating Android notification icons (monochrome for status bar)..."
@for size_dir in "drawable-mdpi:24" "drawable-hdpi:36" "drawable-xhdpi:48" "drawable-xxhdpi:72" "drawable-xxxhdpi:96"; do \
dir=$${size_dir%%:*}; size=$${size_dir##*:}; \
mkdir -p android/app/src/main/res/$$dir; \
magick -size $${size}x$${size} xc:white \
\( assets/icons/icon.png -resize $${size}x$${size} -alpha extract \) \
-compose CopyOpacity -composite \
PNG32:android/app/src/main/res/$$dir/ic_stat_crossbar.png; \
done
@echo "Notification icons generated:"
@ls -la android/app/src/main/res/drawable-*/ic_stat_crossbar.png
@echo ""
@echo "Generating launcher icons (Android, Windows, macOS)..."
dart run flutter_launcher_icons
@echo "Done! All icons generated."
icons-check: ## Validate icon artifacts exist and have correct dimensions
@echo "Checking icon artifacts..."
@ERRORS=0; \
for f in assets/icons/icon.png assets/icons/icon_opaque.png assets/icons/icon_linux.png \
assets/icons/icon_monochrome.png assets/icons/tray_icon_light.png \
assets/icons/tray_icon_dark.png assets/icons/tray_icon_macos.png \
assets/icons/tray_icon.ico assets/icons/com.verseles.crossbar-symbolic.svg; do \
if [ ! -f "$$f" ]; then \
echo "MISSING: $$f"; ERRORS=$$((ERRORS+1)); \
fi; \
done; \
for density in mdpi hdpi xhdpi xxhdpi xxxhdpi; do \
f="android/app/src/main/res/drawable-$$density/ic_stat_crossbar.png"; \
if [ ! -f "$$f" ]; then \
echo "MISSING: $$f"; ERRORS=$$((ERRORS+1)); \
fi; \
done; \
if [ "$$ERRORS" -gt 0 ]; then \
echo "::error::$$ERRORS icon artifacts missing. Run 'make icons' to regenerate."; \
exit 1; \
fi; \
echo "All icon artifacts present."
# Automated release: bump version, commit, tag, push
# Usage: make release V=patch|minor|major
V ?= patch
release: ## Bump version, commit, tag, and push (V=patch|minor|major)
@if [ "$(V)" != "patch" ] && [ "$(V)" != "minor" ] && [ "$(V)" != "major" ]; then \
echo "Invalid version type: $(V). Use V=patch, V=minor, or V=major"; \
exit 1; \
fi
@echo "Releasing $(V) version..."
@# Extract current version from pubspec.yaml
$(eval CURRENT := $(shell grep '^version:' pubspec.yaml | sed 's/version: //'))
$(eval MAJOR := $(shell echo $(CURRENT) | cut -d. -f1))
$(eval MINOR := $(shell echo $(CURRENT) | cut -d. -f2))
$(eval PATCH := $(shell echo $(CURRENT) | cut -d+ -f1 | cut -d. -f3))
$(eval BUILD := $(shell echo $(CURRENT) | cut -d+ -f2))
$(eval NEW_BUILD := $(shell echo $$(($(BUILD)+1))))
@# Calculate new version
$(eval ifeq ($(V),major) \
NEW_VERSION := $(shell echo $$(($(MAJOR)+1))).0.0+$(NEW_BUILD) \
else ifeq ($(V),minor) \
NEW_VERSION := $(MAJOR).$(shell echo $$(($(MINOR)+1))).0+$(NEW_BUILD) \
else \
NEW_VERSION := $(MAJOR).$(MINOR).$(shell echo $$(($(PATCH)+1)))+$(NEW_BUILD) \
endif endif)
@# Fallback calculation using shell
@NEW_VER=$$(python3 -c "\
v='$(CURRENT)'; \
parts=v.split('+'); \
semver=parts[0].split('.'); \
build=int(parts[1])+1; \
maj,mi,pat=int(semver[0]),int(semver[1]),int(semver[2]); \
t='$(V)'; \
maj,mi,pat = (maj+1,0,0) if t=='major' else ((maj,mi+1,0) if t=='minor' else (maj,mi,pat+1)); \
print(f'{maj}.{mi}.{pat}+{build}')"); \
echo "$(CURRENT) -> $$NEW_VER"; \
sed -i "s/^version: .*/version: $$NEW_VER/" pubspec.yaml; \
SEMVER=$$(echo $$NEW_VER | cut -d+ -f1); \
git add pubspec.yaml; \
git commit -m "release: cut v$$SEMVER"; \
git tag "v$$SEMVER"; \
git push && git push --tags; \
echo "Released v$$SEMVER ($$NEW_VER)"