PROJECT_VERSION        := 2.3.2
DOCKER_REPO            := synfinatic
PROJECT_NAME           := aws-sso
DOCKER_PROJECT_NAME    := aws-sso-cli-ecs-server

DIST_DIR ?= dist/
GOOS ?= $(shell uname -s | tr "[:upper:]" "[:lower:]")
ARCH ?= $(shell uname -m)
ifeq ($(ARCH),x86_64)
GOARCH             := amd64
else
GOARCH             := $(ARCH)  # no idea if this works for other platforms....
endif

PROJECT_TAG               := $(shell git describe --tags 2>/dev/null $(git rev-list --tags --max-count=1))
PROJECT_COMMIT            := $(shell git rev-parse HEAD || echo "")
PROJECT_DELTA             := $(shell DELTA_LINES=$$(git diff | wc -l); if [ $${DELTA_LINES} -ne 0 ]; then echo $${DELTA_LINES} ; else echo "''" ; fi)

BUILDINFOSDET ?=
PROGRAM_ARGS ?=
# Set to 1 to enable CGO (required for 1Password support on Linux; produces glibc-linked binary)
CGO_ENABLED ?= 0
ifeq ($(PROJECT_TAG),)
PROJECT_TAG               := NO-TAG
endif
ifeq ($(PROJECT_COMMIT),)
PROJECT_COMMIT            := NO-CommitID
endif
ifeq ($(PROJECT_DELTA),)
PROJECT_DELTA             :=
endif

VERSION_PKG               := $(shell echo $(PROJECT_VERSION) | sed 's/^v//g')
LICENSE                   := GPLv3
URL                       := https://github.com/$(DOCKER_REPO)/$(PROJECT_NAME)
DESCRIPTION               := AWS SSO CLI
BUILDINFOS                ?= $(shell date +%FT%T%z)$(BUILDINFOSDET)
LDFLAGS                   := -X "main.Version=$(PROJECT_VERSION)" -X "main.Delta=$(PROJECT_DELTA)" -X "main.Buildinfos=$(BUILDINFOS)" -X "main.Tag=$(PROJECT_TAG)" -X "main.CommitID=$(PROJECT_COMMIT)"
OUTPUT_NAME               := $(DIST_DIR)$(PROJECT_NAME)-$(PROJECT_VERSION)  # default for current platform
GOLANGCI_LINT_VERSION     := 2.10.1

#ifeq ($(GOOS),darwin)
# https://github.com/golang/go/issues/61229#issuecomment-1988965927
# this doesn't work for homebrew with clang it seems: https://github.com/Homebrew/homebrew-core/pull/174439
#LDFLAGS := $(LDFLAGS) -extldflags=-Wl,-ld_classic
#endif

# go build flags
GOBFLAGS                  := -trimpath

# supported platforms for `make release`
WINDOWS_BIN               := $(DIST_DIR)$(PROJECT_NAME)-$(PROJECT_VERSION)-windows-amd64.exe
WINDOWS32_BIN             := $(DIST_DIR)$(PROJECT_NAME)-$(PROJECT_VERSION)-windows-386.exe
LINUX_BIN                 := $(DIST_DIR)$(PROJECT_NAME)-$(PROJECT_VERSION)-linux-amd64
LINUXARM64_BIN            := $(DIST_DIR)$(PROJECT_NAME)-$(PROJECT_VERSION)-linux-arm64
DARWIN_BIN                := $(DIST_DIR)$(PROJECT_NAME)-$(PROJECT_VERSION)-darwin-amd64
DARWINARM64_BIN           := $(DIST_DIR)$(PROJECT_NAME)-$(PROJECT_VERSION)-darwin-arm64

ALL: $(DIST_DIR)$(PROJECT_NAME) ## Build binary for this platform

include help.mk  # place after ALL target and before all other targets

.PHONY: .build_files
.build_files: $(wildcard */*.go */*/*.go */*/*/*.go) go.mod go.sum .prepare

$(DIST_DIR)$(PROJECT_NAME): .build_files
	go build $(GOBFLAGS) -ldflags='$(LDFLAGS)' -o $(DIST_DIR)$(PROJECT_NAME) ./cmd/aws-sso/...
	@echo "Created: $(DIST_DIR)$(PROJECT_NAME)"

INSTALL_PREFIX ?= /usr/local

install: $(DIST_DIR)$(PROJECT_NAME)  ## install binary in $INSTALL_PREFIX
	install -d $(INSTALL_PREFIX)/bin
	install -c $(DIST_DIR)$(PROJECT_NAME) $(INSTALL_PREFIX)/bin

uninstall:  ## Uninstall binary from $INSTALL_PREFIX
	rm $(INSTALL_PREFIX)/bin/$(PROJECT_NAME)

release-check:  ## Check if we are good to release
	@echo "Checking for v$(PROJECT_VERSION)..."
	@VERSION=$(PROJECT_VERSION) ./scripts/release-check.sh

release-tag: ## Tag our current HEAD as v$(PROJECT_VERSION)
	git tag -sa v$(PROJECT_VERSION) -m 'release $(PROJECT_VERSION)'
	VERSION=$(PROJECT_VERSION) ./scripts/release-check.sh
	git push --tags

#DOWNLOAD_URL := https://synfin.net/misc/aws-sso-cli.$(PROJECT_VERSION).tar.gz
DOWNLOAD_URL ?= https://github.com/synfinatic/aws-sso-cli/archive/refs/tags/v$(PROJECT_VERSION).tar.gz

.PHONY: .shasum
.shasum:
	@which shasum >/dev/null || (echo "Missing 'shasum' binary" ; exit 1)
	@echo "foo" | shasum -a 256 >/dev/null || (echo "'shasum' does not support: -a 256"; exit 1)


.PHONY: package
package: linux linux-arm64  ## Build deb/rpm packages
	docker build -t aws-sso-cli-builder:latest -f Dockerfile.package .
	docker run --rm \
		-v $$(pwd)/dist:/root/dist \
		-e VERSION=$(PROJECT_VERSION) aws-sso-cli-builder:latest

tags: cmd/*/*.go internal/*/*.go internal/*/*/*.go ## Create tags file for vim, etc
	@echo Make sure you have Go Tags installed: https://github.com/jstemmer/gotags
	gotags -f tags -sort=true $$(find . -type f -name "*.go")


.build-release: windows windows32 linux linux-arm64 darwin darwin-arm64

.validate-release: ALL
	@TAG=$$(./$(DIST_DIR)$(PROJECT_NAME) version 2>/dev/null | grep '(v$(PROJECT_VERSION))'); \
		if test -z "$$TAG"; then \
		echo "Build tag from does not match PROJECT_VERSION=v$(PROJECT_VERSION) in Makefile:" ; \
		./$(DIST_DIR)$(PROJECT_NAME) version 2>/dev/null | grep built ; \
		exit 1 ; \
	fi

release: .validate-release .shasum clean .build-release package ## Build all our release binaries
	cd dist && shasum -a 256 * | gpg --clear-sign >release.sig.asc

.PHONY: run
run:  ## build and run using $PROGRAM_ARGS
	go run ./cmd/aws-sso $(PROGRAM_ARGS)

.PHONY: delve
delve: ## debug binary using $PROGRAM_ARGS
	dlv debug ./cmd/aws-sso -- $(PROGRAM_ARGS)

clean-all: clean ## clean _everything_

clean: ## Remove all binaries in dist
	rm -rf dist/*

clean-go: ## Clean Go cache
	go clean -i -r -cache -modcache

go-get:  ## Get our go modules
	go get -v all

.prepare: $(DIST_DIR)

.PHONY: build-race
build-race: .prepare ## Build race detection binary
	go build -race -ldflags='$(LDFLAGS)' -o $(OUTPUT_NAME) ./cmd/aws-sso/...

debug: .prepare ## Run debug in dlv
	dlv debug ./cmd/aws-sso

.PHONY: unittest
unittest: ## Run go unit tests
	go test -ldflags='$(LDFLAGS)' ./...

.PHONY: e2e
e2e: ## Run end-to-end tests against mock AWS HTTP servers
	go test -tags e2etests -ldflags='$(LDFLAGS)' ./cmd/aws-sso/...

coverage: coverage.out
coverage.out: .build_files
	go test -tags e2etests -ldflags='$(LDFLAGS)' -covermode=atomic -coverprofile=coverage.out ./...
	@echo "total coverage (all files): $$(go tool cover -func=coverage.out | grep ^total | sed -Ee 's/.*[^0-9]([0-9]+\.[0-9]%$$)/\1/')"

.PHONY: test-race
test-race: ## Run `go test -race` on the code
	@echo checking code for races...
	go test -race ./...

.PHONY: vet
vet: ## Run `go vet` on the code
	@echo checking code is vetted...
	@for x in $(shell go list ./...); do echo $$x ; go vet $$x || exit $$?; done

test: vet unittest lint test-homebrew test-tidy test-fmt ## Run important tests

precheck: test test-fmt test-tidy ## Run all tests that happen in a PR

govulncheck:  ## Run govulncheck
	@govulncheck ./...

# run everything but `lint`and govulncheck because they run seperately
.build-tests: vet coverage test-tidy test-fmt test-homebrew

$(DIST_DIR):
	@if test ! -d $(DIST_DIR); then mkdir -p $(DIST_DIR) ; fi

.PHONY: fmt
fmt: ## Format Go code
	@gofmt -s -w */*/*.go

.PHONY: test-fmt
test-fmt: fmt ## Test to make sure code if formatted correctly
	@if test `git diff cmd/aws-sso | wc -l` -gt 0; then \
	    echo "Code changes detected when running 'go fmt':" ; \
	    git diff -Xfiles ; \
	    exit -1 ; \
	fi

.PHONY: test-tidy
test-tidy:  ## Test to make sure go.mod is tidy
	@go mod tidy
	@if test `git diff go.mod | wc -l` -gt 0; then \
	    echo "Need to run 'go mod tidy' to clean up go.mod" ; \
	    exit -1 ; \
	fi

lint: .lint-check  ## Run golangci-lint
	golangci-lint run

lint-install:  ## Install golangci-lint
	curl -sSfL https://golangci-lint.run/install.sh | sh -s -- -b $(shell go env GOPATH)/bin v$(GOLANGCI_LINT_VERSION)

.PHONY: .print-golangci-lint-version
.print-golangci-lint-version:  ## Print golangci-lint version
	@echo v$(GOLANGCI_LINT_VERSION)

.PHONY: .lint-check
.lint-check:
	@if test $$(golangci-lint --version 2>&1 | grep -c "version $(GOLANGCI_LINT_VERSION)") -eq 0 ; then \
	   echo "Need to install golangci-lint $(GOLANGCI_LINT_VERSION)" ; \
	   echo "Run: make lint-install" ; \
	   exit -1 ; \
	fi
	

test-homebrew: $(DIST_DIR)$(PROJECT_NAME)  ## Run the homebrew tests
	@$(DIST_DIR)$(PROJECT_NAME) --config /dev/null version 2>/dev/null | grep -q "AWS SSO CLI Version $(PROJECT_VERSION)"
	@$(DIST_DIR)$(PROJECT_NAME) --config /dev/null 2>&1 | grep -q "no AWS SSO providers have been configured"

# Build targets for our supported plaforms
windows: $(WINDOWS_BIN)  ## Build 64bit x86 Windows binary

$(WINDOWS_BIN): .build_files
	GOARCH=amd64 GOOS=windows go build $(GOBFLAGS) -ldflags='$(LDFLAGS)' -o $(WINDOWS_BIN) ./cmd/aws-sso/...
	@echo "Created: $(WINDOWS_BIN)"

windows32: $(WINDOWS32_BIN)  ## Build 32bit x86 Windows binary

$(WINDOWS32_BIN): .build_files
	GOARCH=386 GOOS=windows go build $(GOBFLAGS) -ldflags='$(LDFLAGS)' -o $(WINDOWS32_BIN) ./cmd/aws-sso/...
	@echo "Created: $(WINDOWS32_BIN)"

linux: $(LINUX_BIN)  ## Build Linux/x86_64 binary

$(LINUX_BIN): .build_files
	CGO_ENABLED=$(CGO_ENABLED) GOARCH=amd64 GOOS=linux go build $(GOBFLAGS) -ldflags='$(LDFLAGS)' -o $(LINUX_BIN) ./cmd/aws-sso/...
	@echo "Created: $(LINUX_BIN)"

linux-arm64: $(LINUXARM64_BIN)  ## Build Linux/arm64 binary

$(LINUXARM64_BIN): .build_files
	CGO_ENABLED=$(CGO_ENABLED) GOARCH=arm64 GOOS=linux go build $(GOBFLAGS) -ldflags='$(LDFLAGS)' -o $(LINUXARM64_BIN) ./cmd/aws-sso/...
	@echo "Created: $(LINUXARM64_BIN)"

# macOS needs different build flags if you are cross-compiling because of the key chain
# See: https://github.com/99designs/aws-vault/issues/758

darwin: $(DARWIN_BIN)  ## Build MacOS/x86_64 binary

$(DARWIN_BIN): .build_files
ifeq ($(ARCH), x86_64)
	CGO_ENABLED=1 GOARCH=amd64 GOOS=darwin go build $(GOBFLAGS) -ldflags='$(LDFLAGS)' -o $(DARWIN_BIN) ./cmd/aws-sso/...
else
	CGO_ENABLED=1 GOARCH=amd64 GOOS=darwin SDKROOT=$(shell xcrun --sdk macosx --show-sdk-path) \
		go build $(GOBFLAGS) -ldflags='$(LDFLAGS)' -o $(DARWIN_BIN) ./cmd/aws-sso/...
endif
	@echo "Created: $(DARWIN_BIN)"

darwin-arm64: $(DARWINARM64_BIN)  ## Build MacOS/ARM64 binary

$(DARWINARM64_BIN): .build_files
ifeq ($(ARCH), arm64)
	CGO_ENABLED=1 GOARCH=arm64 GOOS=darwin go build $(GOBFLAGS) -ldflags='$(LDFLAGS)' -o $(DARWINARM64_BIN) ./cmd/aws-sso/...
else
	CGO_ENABLED=1 GOARCH=arm64 GOOS=darwin SDKROOT=$(shell xcrun --sdk macosx --show-sdk-path) \
		go build $(GOBFLAGS) -ldflags='$(LDFLAGS)' -o $(DARWINARM64_BIN) ./cmd/aws-sso/...
endif
	@echo "Created: $(DARWINARM64_BIN)"

$(OUTPUT_NAME): .build_files
	go build $(GOBFLAGS) -ldflags='$(LDFLAGS)' -o $(OUTPUT_NAME) ./cmd/aws-sso/...

docs: docs/default-region.png  ## Build document files

docs/default-region.png: docs/default-region.dot
	dot -o docs/default-region.png -Tpng docs/default-region.dot

.PHONY: loc
loc:  ## Print LOC stats
	wc -l $$(find . -name "*.go")

YEAR := $(shell echo $$(date +%Y))
LAST_YEAR := $(shell echo $$(($$(date +%Y)-1)))

update-copyright:  ## Update the copyright year on *.go
	sed -i '' -Ee "s|2021-$(LAST_YEAR)|2021-$(YEAR)|" $$(find . -name "*.go") mkdocs.yml
	@echo "Updated copyright to 2021-$(YEAR)"

serve-docs:  ## Run mkdocs server on localhost:8000
	docker build -t synfinatic/mkdocs-material:latest -f Dockerfile.mkdocs .
	docker run --rm \
		-v $$(pwd):/docs \
		-p 8000:8000 \
		synfinatic/mkdocs-material:latest

docker:  ## Build docker image
	docker build -t $(DOCKER_REPO)/$(DOCKER_PROJECT_NAME):v$(PROJECT_VERSION) \
		-t $(DOCKER_REPO)/$(DOCKER_PROJECT_NAME):latest .
