# SubConverter-Go Makefile # This Makefile contains common commands for building, testing, and managing the SubConverter-Go project # Project variables PROJECT_NAME := subconverter-go VERSION := 1.0.0 BUILD_TIME := $(shell date -u '+%Y-%m-%d %H:%M:%S') GIT_COMMIT := $(shell git rev-parse --short HEAD) GIT_DIRTY := $(shell test -n "`git status --porcelain`" && echo "+CHANGES" || true) LDFLAGS := "-ldflags=-X 'main.Version=$(VERSION)' -X 'main.BuildTime=$(BUILD_TIME)' -X 'main.GitCommit=$(GIT_COMMIT)$(GIT_DIRTY)'" # Build variables GO := go GOOS ?= $(shell go env GOOS) GOARCH ?= $(shell go env GOARCH) BUILD_DIR := build DIST_DIR := dist CONFIG_FILE := config.yaml # Command variables SHELL := /bin/bash RM := rm -rf MKDIR := mkdir -p CP := cp -r FIND := find XARGS := xargs # Default target .PHONY: all all: clean build test # Help target - show available commands .PHONY: help help: ## Show this help message @echo "SubConverter-Go Development Commands:" @echo "" @awk 'BEGIN {FS = ":.*##"; printf "%-20s %s\n", "Target", "Description"} /^[a-zA-Z_-]+:.*?##/ { printf "%-20s %s\n", $$1, $$2 }' $(MAKEFILE_LIST) # Build targets .PHONY: build build: ## Build the application for current platform @echo "Building $(PROJECT_NAME) for $(GOOS)/$(GOARCH)..." $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(PROJECT_NAME) main.go @echo "Build complete: $(BUILD_DIR)/$(PROJECT_NAME)" .PHONY: build-all build-all: ## Build the application for all supported platforms @echo "Building $(PROJECT_NAME) for all platforms..." $(MKDIR) $(DIST_DIR) @for os in linux darwin windows; do \ for arch in amd64 arm64; do \ if [ "$$os" = "windows" ]; then \ ext=".exe"; \ else \ ext=""; \ fi; \ echo "Building for $$os/$$arch..."; \ GOOS=$$os GOARCH=$$arch $(GO) build $(LDFLAGS) \ -o $(DIST_DIR)/$(PROJECT_NAME)-$$os-$$arch$$ext main.go; \ done; \ done @echo "All builds complete in $(DIST_DIR)/" .PHONY: build-linux build-linux: ## Build the application for Linux @echo "Building $(PROJECT_NAME) for Linux..." GOOS=linux GOARCH=amd64 $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(PROJECT_NAME)-linux main.go @echo "Build complete: $(BUILD_DIR)/$(PROJECT_NAME)-linux" .PHONY: build-darwin build-darwin: ## Build the application for macOS @echo "Building $(PROJECT_NAME) for macOS..." GOOS=darwin GOARCH=amd64 $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(PROJECT_NAME)-darwin main.go @echo "Build complete: $(BUILD_DIR)/$(PROJECT_NAME)-darwin" .PHONY: build-windows build-windows: ## Build the application for Windows @echo "Building $(PROJECT_NAME) for Windows..." GOOS=windows GOARCH=amd64 $(GO) build $(LDFLAGS) -o $(BUILD_DIR)/$(PROJECT_NAME)-windows.exe main.go @echo "Build complete: $(BUILD_DIR)/$(PROJECT_NAME)-windows.exe" # Development targets .PHONY: dev dev: ## Run the application in development mode @echo "Starting $(PROJECT_NAME) in development mode..." $(GO) run main.go --config $(CONFIG_FILE) .PHONY: dev-watch dev-watch: ## Run the application with file watching (requires air) @echo "Starting $(PROJECT_NAME) with file watching..." @if command -v air >/dev/null 2>&1; then \ air; \ else \ echo "Installing air for hot reload..."; \ $(GO) install github.com/cosmtrek/air@latest; \ air; \ fi # Test targets .PHONY: test test: ## Run all tests @echo "Running all tests..." $(GO) test -v ./... .PHONY: test-unit test-unit: ## Run unit tests only @echo "Running unit tests..." $(GO) test -v ./tests/unit/... .PHONY: test-integration test-integration: ## Run integration tests only @echo "Running integration tests..." $(GO) test -v ./tests/integration/... .PHONY: test-contract test-contract: ## Run contract tests only @echo "Running contract tests..." $(GO) test -v ./tests/contract/... .PHONY: test-coverage test-coverage: ## Run tests with coverage report @echo "Running tests with coverage..." $(GO) test -v -coverprofile=coverage.out ./... $(GO) tool cover -html=coverage.out -o coverage.html @echo "Coverage report generated: coverage.html" .PHONY: test-race test-race: ## Run tests with race condition detection @echo "Running tests with race detection..." $(GO) test -race -v ./... .PHONY: benchmark benchmark: ## Run benchmarks @echo "Running benchmarks..." $(GO) test -bench=. -benchmem ./... # Quality targets .PHONY: lint lint: ## Run linter to check code quality @echo "Running linter..." @if command -v golangci-lint >/dev/null 2>&1; then \ golangci-lint run; \ else \ echo "Installing golangci-lint..."; \ curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(shell go env GOPATH)/bin v1.54.2; \ golangci-lint run; \ fi .PHONY: fmt fmt: ## Format Go code @echo "Formatting Go code..." $(GO) fmt ./... .PHONY: fmt-check fmt-check: ## Check if Go code is properly formatted @echo "Checking Go code formatting..." @if [ $$($(GO) fmt ./... | wc -l) -gt 0 ]; then \ echo "Go code is not formatted. Run 'make fmt' to fix."; \ $(GO) fmt -d ./...; \ exit 1; \ else \ echo "Go code is properly formatted."; \ fi .PHONY: vet vet: ## Run go vet to check for common issues @echo "Running go vet..." $(GO) vet ./... # Dependency management .PHONY: deps deps: ## Download and install dependencies @echo "Downloading dependencies..." $(GO) mod download $(GO) mod tidy .PHONY: deps-update deps-update: ## Update dependencies to latest versions @echo "Updating dependencies..." $(GO) get -u ./... $(GO) mod tidy .PHONY: deps-check deps-check: ## Check for security vulnerabilities in dependencies @echo "Checking for security vulnerabilities..." @if command -v govulncheck >/dev/null 2>&1; then \ govulncheck ./...; \ else \ echo "Installing govulncheck..."; \ $(GO) install golang.org/x/vuln/cmd/govulncheck@latest; \ govulncheck ./...; \ fi # Documentation targets .PHONY: docs docs: ## Generate documentation @echo "Generating documentation..." @if command -v godoc >/dev/null 2>&1; then \ echo "Starting documentation server on :6060..."; \ godoc -http=:6060 & \ echo "Documentation available at http://localhost:6060/pkg/github.com/subconverter-go/"; \ else \ echo "godoc not available. Install with: go install golang.org/x/tools/cmd/godoc@latest"; \ fi .PHONY: swagger swagger: ## Generate Swagger documentation (requires swag) @echo "Generating Swagger documentation..." @if command -v swag >/dev/null 2>&1; then \ swag init -g ./main.go -o ./docs/swagger; \ echo "Swagger documentation generated in docs/swagger/"; \ else \ echo "Installing swag..."; \ $(GO) install github.com/swaggo/swag/cmd/swag@latest; \ swag init -g ./main.go -o ./docs/swagger; \ fi # Docker targets .PHONY: docker-build docker-build: ## Build Docker image @echo "Building Docker image..." docker build -t $(PROJECT_NAME):$(VERSION) . docker build -t $(PROJECT_NAME):latest . .PHONY: docker-run docker-run: ## Run Docker container @echo "Running Docker container..." docker run -p 25500:25500 -v $(PWD)/config.yaml:/app/config.yaml $(PROJECT_NAME):latest .PHONY: docker-push docker-push: ## Push Docker image to registry @echo "Pushing Docker image..." docker push $(PROJECT_NAME):$(VERSION) docker push $(PROJECT_NAME):latest # Installation targets .PHONY: install install: ## Install the application locally @echo "Installing $(PROJECT_NAME)..." $(GO) install $(LDFLAGS) . .PHONY: uninstall uninstall: ## Uninstall the application locally @echo "Uninstalling $(PROJECT_NAME)..." $(RM) $(shell go env GOPATH)/bin/$(PROJECT_NAME) # Configuration targets .PHONY: config config: ## Generate default configuration file @echo "Generating default configuration..." @printf "# SubConverter-Go Configuration\n" > $(CONFIG_FILE) @printf "server:\n" >> $(CONFIG_FILE) @printf " port: 25500\n" >> $(CONFIG_FILE) @printf " host: \"0.0.0.0\"\n" >> $(CONFIG_FILE) @printf " read_timeout: 30\n" >> $(CONFIG_FILE) @printf " write_timeout: 30\n" >> $(CONFIG_FILE) @printf " max_request_size: 10485760\n" >> $(CONFIG_FILE) @printf "\n" >> $(CONFIG_FILE) @printf "logging:\n" >> $(CONFIG_FILE) @printf " level: \"info\"\n" >> $(CONFIG_FILE) @printf " format: \"json\"\n" >> $(CONFIG_FILE) @printf " output: \"stdout\"\n" >> $(CONFIG_FILE) @printf " file: \"logs/subconverter-go.log\"\n" >> $(CONFIG_FILE) @printf " max_size: 100\n" >> $(CONFIG_FILE) @printf " max_age: 7\n" >> $(CONFIG_FILE) @printf " max_backups: 3\n" >> $(CONFIG_FILE) @printf " compress: true\n" >> $(CONFIG_FILE) @printf "\n" >> $(CONFIG_FILE) @printf "security:\n" >> $(CONFIG_FILE) @printf " access_tokens: []\n" >> $(CONFIG_FILE) @printf " cors_origins: [\"*\"]\n" >> $(CONFIG_FILE) @printf " rate_limit: 60\n" >> $(CONFIG_FILE) @printf " timeout: 60\n" >> $(CONFIG_FILE) @printf "\n" >> $(CONFIG_FILE) @printf "conversion:\n" >> $(CONFIG_FILE) @printf " default_target: \"clash\"\n" >> $(CONFIG_FILE) @printf " supported_targets:\n" >> $(CONFIG_FILE) @printf " - \"clash\"\n" >> $(CONFIG_FILE) @printf " - \"surge\"\n" >> $(CONFIG_FILE) @printf " - \"quantumult-x\"\n" >> $(CONFIG_FILE) @printf " - \"loon\"\n" >> $(CONFIG_FILE) @printf " - \"surfboard\"\n" >> $(CONFIG_FILE) @printf " - \"v2ray\"\n" >> $(CONFIG_FILE) @printf " default_emoji: false\n" >> $(CONFIG_FILE) @printf " default_udp: false\n" >> $(CONFIG_FILE) @printf " max_nodes: 0\n" >> $(CONFIG_FILE) @printf " cache_timeout: 60\n" >> $(CONFIG_FILE) @echo "Configuration file created: $(CONFIG_FILE)" # Clean targets .PHONY: clean clean: ## Clean build artifacts @echo "Cleaning build artifacts..." $(RM) $(BUILD_DIR) $(RM) $(DIST_DIR) $(RM) coverage.out $(RM) coverage.html .PHONY: clean-cache clean-cache: ## Clean Go module cache @echo "Cleaning Go module cache..." $(GO) clean -cache $(GO) clean -modcache $(RM) -rf $(shell go env GOPATH)/pkg/mod .PHONY: clean-logs clean-logs: ## Clean log files @echo "Cleaning log files..." $(RM) -rf logs/ # Release targets .PHONY: release release: clean build-all ## Create release package @echo "Creating release package..." $(MKDIR) $(DIST_DIR)/release $(CP) $(CONFIG_FILE) $(DIST_DIR)/release/ $(CP) README.md $(DIST_DIR)/release/ 2>/dev/null || true $(CP) LICENSE $(DIST_DIR)/release/ 2>/dev/null || true cd $(DIST_DIR) && tar -czf $(PROJECT_NAME)-$(VERSION)-$(GOOS)-$(GOARCH).tar.gz release/* @echo "Release package created: $(DIST_DIR)/$(PROJECT_NAME)-$(VERSION)-$(GOOS)-$(GOARCH).tar.gz" # Monitoring and debugging .PHONY: run run: build ## Build and run the application @echo "Building and running $(PROJECT_NAME)..." $(BUILD_DIR)/$(PROJECT_NAME) --config $(CONFIG_FILE) .PHONY: run-debug run-debug: build ## Build and run the application in debug mode @echo "Building and running $(PROJECT_NAME) in debug mode..." DEBUG=true $(BUILD_DIR)/$(PROJECT_NAME) --config $(CONFIG_FILE) .PHONY: profile profile: ## Run application with profiling @echo "Running $(PROJECT_NAME) with profiling..." $(GO) run main.go --config $(CONFIG_FILE) --enable-profiling # CI/CD targets .PHONY: ci ci: deps fmt-check vet test ## Run CI pipeline checks @echo "Running CI pipeline..." .PHONY: pre-commit pre-commit: fmt-check vet lint test ## Run pre-commit checks @echo "Running pre-commit checks..." # Utility targets .PHONY: version version: ## Show version information @echo "$(PROJECT_NAME) version $(VERSION)" @echo "Build time: $(BUILD_TIME)" @echo "Git commit: $(GIT_COMMIT)$(GIT_DIRTY)" .PHONY: info info: ## Show project information @echo "Project: $(PROJECT_NAME)" @echo "Version: $(VERSION)" @echo "Go version: $(shell $(GO) version)" @echo "GOOS: $(GOOS)" @echo "GOARCH: $(GOARCH)" @echo "Working directory: $(PWD)" .PHONY: tree tree: ## Show project directory tree @echo "Project directory tree:" @$(FIND) . -type f -name "*.go" -o -name "*.md" -o -name "*.yaml" -o -name "*.yml" -o -name "Makefile" | \ sort | sed 's|[^/]*/| |g' # Development environment setup .PHONY: setup setup: deps config ## Setup development environment @echo "Setting up development environment..." @echo "Installing development tools..." @if ! command -v golangci-lint >/dev/null 2>&1; then \ echo "Installing golangci-lint..."; \ curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(shell go env GOPATH)/bin v1.54.2; \ fi @if ! command -v air >/dev/null 2>&1; then \ echo "Installing air (hot reload)..."; \ $(GO) install github.com/cosmtrek/air@latest; \ fi @if ! command -v swag >/dev/null 2>&1; then \ echo "Installing swag (Swagger generator)..."; \ $(GO) install github.com/swaggo/swag/cmd/swag@latest; \ fi @echo "Development environment setup complete!" # Check if required files exist .PHONY: check check: ## Check if required files exist @echo "Checking required files..." @if [ ! -f "main.go" ]; then \ echo "❌ main.go not found"; \ exit 1; \ fi @if [ ! -f "$(CONFIG_FILE)" ]; then \ echo "⚠️ $(CONFIG_FILE) not found. Run 'make config' to create it."; \ fi @if [ ! -f "go.mod" ]; then \ echo "❌ go.mod not found"; \ exit 1; \ fi @if [ ! -f "Makefile" ]; then \ echo "❌ Makefile not found"; \ exit 1; \ fi @echo "✅ All required files are present" # Create development scripts .PHONY: scripts scripts: ## Create development scripts @echo "Creating development scripts..." @mkdir -p scripts @printf "#!/bin/bash\n" > scripts/dev.sh @printf "# Development script for SubConverter-Go\n" >> scripts/dev.sh @printf "set -e\n" >> scripts/dev.sh @printf "\n" >> scripts/dev.sh @printf "echo \"🚀 Starting SubConverter-Go in development mode...\"\n" >> scripts/dev.sh @printf "go run main.go --config config.yaml\n" >> scripts/dev.sh @chmod +x scripts/dev.sh @printf "#!/bin/bash\n" > scripts/test.sh @printf "# Test script for SubConverter-Go\n" >> scripts/test.sh @printf "set -e\n" >> scripts/test.sh @printf "\n" >> scripts/test.sh @printf "echo \"🧪 Running all tests...\"\n" >> scripts/test.sh @printf "go test -v ./...\n" >> scripts/test.sh @printf "echo \"✅ All tests passed!\"\n" >> scripts/test.sh @chmod +x scripts/test.sh @printf "#!/bin/bash\n" > scripts/build.sh @printf "# Build script for SubConverter-Go\n" >> scripts/build.sh @printf "set -e\n" >> scripts/build.sh @printf "\n" >> scripts/build.sh @printf "echo \"🔨 Building SubConverter-Go...\"\n" >> scripts/build.sh @printf "make build\n" >> scripts/build.sh @printf "echo \"✅ Build complete!\"\n" >> scripts/build.sh @chmod +x scripts/build.sh @echo "Development scripts created in scripts/" # Backup targets .PHONY: backup backup: ## Create backup of important files @echo "Creating backup..." @tar -czf backup-$(shell date +%Y%m%d-%H%M%S).tar.gz \ --exclude=node_modules \ --exclude=.git \ --exclude=$(BUILD_DIR) \ --exclude=$(DIST_DIR) \ --exclude=coverage* \ --exclude=logs \ . 2>/dev/null || true @echo "Backup created successfully" # Show project statistics .PHONY: stats stats: ## Show project statistics @echo "📊 Project Statistics:" @echo "Go files: $(shell find . -name '*.go' -not -path './vendor/*' | wc -l)" @echo "Total lines: $(shell find . -name '*.go' -not -path './vendor/*' | xargs wc -l | tail -1 | awk '{print $$1}')" @echo "Test files: $(shell find . -name '*_test.go' | wc -l)" @echo "Package count: $(shell go list ./... | wc -l)" @echo "Dependencies: $(shell go list -m all | wc -l)" # Quick start (for new developers) .PHONY: quickstart quickstart: setup test build ## Quick start for new developers @echo "🎉 Quick start complete!" @echo "Run './subconverter-go --config config.yaml' to start the server" @echo "Run 'make help' to see all available commands" # Default target if no target is specified .DEFAULT_GOAL := help # Prevent accidental deletion of files .PHONY: % %: ;