diff --git a/.gitignore b/.gitignore index 80e9db3..044d3f4 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ Verdana.ttf +dist/ +reports/ diff --git a/Makefile b/Makefile index 89fd33e..6795fe2 100644 --- a/Makefile +++ b/Makefile @@ -1,92 +1,222 @@ -################################################################################ - -# This Makefile generated by GoMakeGen 2.2.0 using next command: -# gomakegen --mod . +# This file is intended as a starting point for a customized makefile for a Go project. # -# More info: https://kaos.sh/gomakegen - -################################################################################ - -export GO111MODULE=on - -ifdef VERBOSE ## Print verbose information (Flag) -VERBOSE_FLAG = -v -endif - -MAKEDIR = $(dir $(realpath $(firstword $(MAKEFILE_LIST)))) -GITREV ?= $(shell test -s $(MAKEDIR)/.git && git rev-parse --short HEAD) - -################################################################################ - -.DEFAULT_GOAL := help -.PHONY = fmt vet deps update test init vendor mod-init mod-update mod-download mod-vendor help - -################################################################################ - -init: mod-init ## Initialize new module - -deps: mod-download ## Download dependencies - -update: mod-update ## Update dependencies to the latest versions - -vendor: mod-vendor ## Make vendored copy of dependencies - -test: ## Run tests -ifdef COVERAGE_FILE ## Save coverage data into file (String) - go test $(VERBOSE_FLAG) -covermode=count -coverprofile=$(COVERAGE_FILE) . -else - go test $(VERBOSE_FLAG) -covermode=count . -endif - -mod-init: -ifdef MODULE_PATH ## Module path for initialization (String) - go mod init $(MODULE_PATH) -else - go mod init -endif +# Targets: +# all: Format, check, build, and test the code +# setup: Install build/test toolchain dependencies (e.g. gox) +# lint: Run linters against source code +# bump-{major,minor,patch}: create a new semver git tag +# release-{major,minor,patch}: push a tagged release +# format: Format the source files +# build: Build the command(s) for target OS/arch combinations +# install: Install the command(s) +# clean: Clean the build/test artifacts +# report: Generate build/test reports +# check: Run tests +# bench: Run benchmarks +# dist: zip/tar binaries & documentation +# debug: print parameters +# +# Parameters: +# VERSION: release version in semver format +# BUILD_TAGS: additional build tags to pass to go build +# DISTDIR: path to save distribution files +# RPTDIR: path to save build/test reports +# +# Assumptions: +# - Your package contains a cmd/ package, containing a directory for each produced binary. +# - You have cloc installed and accessible in the PATH. +# - Your GOPATH and GOROOT are set correctly. +# - Your makefile is in the root of your package and does not have a space in its file name. +# - Your root package contains global string variables Version and Build, to receive the bild version number and commit ID, respectively. +# +# Features: +# - report generates files that can be consumed by Jenkins, as well as a list of external dependencies. +# - setup installs all the tools aside from cloc. +# - Works on Windows and with paths containing spaces. +# - Works when executing from outside the makefile directory using -f. +# - Targets are useful both in CI and developer workstations. +# - Handles cross-compiation for multiple OSes and architectures. +# - Bundles binaries and documentation into compressed archives, using tar/gz for Linux and Darwin, and zip for Windows. + + +# Parameters +PKG = code.ndumas.com/ndumas/badges +NAME = badges +DOC = README.md LICENSE + + +# Replace backslashes with forward slashes for use on Windows. +# Make is !@#$ing weird. +E := +BSLASH := \$E +FSLASH := / -ifdef COMPAT ## Compatible Go version (String) - go mod tidy $(VERBOSE_FLAG) -compat=$(COMPAT) -else - go mod tidy $(VERBOSE_FLAG) -endif +# Directories +WD := $(subst $(BSLASH),$(FSLASH),$(shell pwd)) +MD := $(subst $(BSLASH),$(FSLASH),$(shell dirname "$(realpath $(lastword $(MAKEFILE_LIST)))")) +PKGDIR = $(MD) +CMDDIR = $(PKGDIR)/cmd +DISTDIR ?= $(WD)/dist +RPTDIR ?= $(WD)/reports +GP = $(subst $(BSLASH),$(FSLASH),$(GOPATH)) -mod-update: -ifdef UPDATE_ALL ## Update all dependencies (Flag) - go get -u $(VERBOSE_FLAG) all -else - go get -u $(VERBOSE_FLAG) ./... -endif +# Parameters +VERSION ?= $(shell git -C "$(MD)" describe --tags --dirty=-dev) +COMMIT_ID := $(shell git -C "$(MD)" rev-parse HEAD | head -c8) +BUILD_TAGS ?= release +CMDPKG = $(PKG)/cmd +CMDS := $(shell find "$(CMDDIR)/" -mindepth 1 -maxdepth 1 -type d | sed 's/ /\\ /g' | xargs -n1 basename) +BENCHCPUS ?= 1,2,4 -ifdef COMPAT - go mod tidy $(VERBOSE_FLAG) -compat=$(COMPAT) -else - go mod tidy $(VERBOSE_FLAG) -endif +# Commands +GOCMD = go +ARCHES ?= amd64 386 +OSES ?= windows linux darwin +OUTTPL = $(DISTDIR)/$(NAME)-$(VERSION)-{{.OS}}_{{.Arch}}/{{.Dir}} +LDFLAGS = -X $(PKG).Version=$(VERSION) -X $(PKG).Build=$(COMMIT_ID) +GOBUILD = gox -osarch="!darwin/386" -rebuild -gocmd="$(GOCMD)" -arch="$(ARCHES)" -os="$(OSES)" -output="$(OUTTPL)" -tags "$(BUILD_TAGS)" -ldflags "$(LDFLAGS)" +GOCLEAN = $(GOCMD) clean +GOINSTALL = $(GOCMD) install -a -tags "$(BUILD_TAGS)" -ldflags "$(LDFLAGS)" +GOTEST = $(GOCMD) test -race -v -tags "$(BUILD_TAGS)" +DISABLED_LINTERS = varnamelen,interfacer,ifshort,exhaustivestruct,maligned,varcheck,scopelint,structcheck,deadcode,nosnakecase,golint,depguard +GOLINT = golangci-lint run --enable-all --disable "$(DISABLED_LINTERS)" --timeout=30s --tests +GODEP = $(GOCMD) get -d -t +GOFMT = goreturns -w +GOBENCH = $(GOCMD) test -v -tags "$(BUILD_TAGS)" -cpu=$(BENCHCPUS) -run=NOTHING -bench=. -benchmem -outputdir "$(RPTDIR)" +GZCMD = tar -czf +ZIPCMD = zip +SHACMD = sha256sum +SLOCCMD = cloc --by-file --xml --exclude-dir="vendor" --include-lang="Go" +XUCMD = go2xunit +DOCKER_CMD=docker --config ~/.docker/ + +# Dynamic Targets +INSTALL_TARGETS := $(addprefix install-,$(CMDS)) + +.PHONY: all + +all: debug setup dep format lint test bench build dist + +git-push: + git push origin main --tags + +release-major: bump-major git-push + +release-minor: bump-minor git-push + +release-patch: bump-patch git-push + + +setup: setup-dirs setup-build setup-format setup-lint setup-reports setup-bump setup-stringer + +setup-stringer: + go install golang.org/x/tools/cmd/stringer@latest + +setup-bump: + go install github.com/guilhem/bump@latest + +bump-major: setup-bump + bump major + +bump-minor: setup-bump + bump minor + +bump-patch: setup-bump + bump patch + +setup-reports: setup-dirs + go install github.com/tebeka/go2xunit@latest + +setup-build: setup-dirs + go install github.com/mitchellh/gox@latest + +setup-format: setup-dirs + go install github.com/sqs/goreturns@latest + +setup-lint: setup-dirs + go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.53.1 + +setup-dirs: + mkdir -p "$(RPTDIR)" + mkdir -p "$(DISTDIR)" + +clean: + $(GOCLEAN) $(PKG) + rm -vrf "$(DISTDIR)"/* + rm -vf "$(RPTDIR)"/* + +format: + $(GOFMT) "$(PKGDIR)" + +dep: + $(GODEP) $(PKG)/... + +gen: + $(GOCMD) generate + +lint: setup-dirs dep + $(GOLINT) "$(PKGDIR)" | tee "$(RPTDIR)/lint.out" + +check: setup-dirs clean dep setup-stringer gen + $(GOTEST) $$(go list "$(PKG)/..." | grep -v /vendor/) | tee "$(RPTDIR)/test.out" + +bench: setup-dirs clean dep + $(GOBENCH) $$(go list "$(PKG)/..." | grep -v /vendor/) | tee "$(RPTDIR)/bench.out" + +report: check + cd "$(PKGDIR)";$(SLOCCMD) --out="$(RPTDIR)/cloc.xml" . | tee "$(RPTDIR)/cloc.out" + cat "$(RPTDIR)/test.out" | $(XUCMD) -output "$(RPTDIR)/tests.xml" + go list -f '{{join .Deps "\n"}}' "$(CMDPKG)/..." | sort | uniq | xargs -I {} sh -c "go list -f '{{if not .Standard}}{{.ImportPath}}{{end}}' {} | tee -a '$(RPTDIR)/deps.out'" + +build: $(CMDS) +$(CMDS): setup-dirs dep + $(GOBUILD) "$(CMDPKG)/$@" | tee "$(RPTDIR)/build-$@.out" +install: $(INSTALL_TARGETS) +$(INSTALL_TARGETS): + $(GOINSTALL) "$(CMDPKG)/$(subst install-,,$@)" - test -d vendor && rm -rf vendor && go mod vendor $(VERBOSE_FLAG) || : +dist: clean build + for docfile in $(DOC); do \ + for dir in "$(DISTDIR)"/*; do \ + cp "$(PKGDIR)/$$docfile" "$$dir/"; \ + done; \ + done + cd "$(DISTDIR)"; for dir in ./*linux*; do $(GZCMD) "$(basename "$$dir").tar.gz" "$$dir"; done + cd "$(DISTDIR)"; for dir in ./*windows*; do $(ZIPCMD) "$(basename "$$dir").zip" "$$dir"; done + cd "$(DISTDIR)"; for dir in ./*darwin*; do $(GZCMD) "$(basename "$$dir").tar.gz" "$$dir"; done + cd "$(DISTDIR)"; find . -maxdepth 1 -type f -printf "$(SHACMD) %P | tee \"./%P.sha\"\n" | sh + $(info "Built v$(VERSION), build $(COMMIT_ID)") -mod-download: - go mod download -mod-vendor: - rm -rf vendor && go mod vendor $(VERBOSE_FLAG) +.PHONY: docker +docker: docker-image docker-push -fmt: ## Format source code with gofmt - find . -name "*.go" -exec gofmt -s -w {} \; +.PHONY: docker-push +docker-push: + $(DOCKER_CMD) tag $(PKG):$(VERSION) $(PKG):latest + $(DOCKER_CMD) push $(PKG):latest + $(DOCKER_CMD) push $(PKG):$(VERSION) -vet: ## Runs 'go vet' over sources - go vet -composites=false -printfuncs=LPrintf,TLPrintf,TPrintf,log.Debug,log.Info,log.Warn,log.Error,log.Critical,log.Print ./... +.PHONY: docker-image +docker-image: + $(DOCKER_CMD) build --build-arg VERSION=$(VERSION) -t $(PKG):$(VERSION) . -help: ## Show this info - @echo -e '\n\033[1mTargets:\033[0m\n' - @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) \ - | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[33m%-14s\033[0m %s\n", $$1, $$2}' - @echo -e '\n\033[1mVariables:\033[0m\n' - @grep -E '^ifdef [A-Z_]+ .*?## .*$$' $(abspath $(lastword $(MAKEFILE_LIST))) \ - | sed 's/ifdef //' \ - | awk 'BEGIN {FS = " .*?## "}; {printf " \033[32m%-14s\033[0m %s\n", $$1, $$2}' - @echo -e '' - @echo -e '\033[90mGenerated by GoMakeGen 2.2.0\033[0m\n' +.PHONY: build-alpine +build-alpine: +# this version breaks build variable injection +# CGO_ENABLED=0 GOOS=linux go build -ldflags="buildmode=exe $(LDFLAGS) -linkmode external -w -extldflags '-static' " -o $(DISTDIR)/$(NAME)-$(VERSION)-alpine/obp cmd/obp/*.go + CGO_ENABLED=0 GOOS=linux go build -ldflags="$(LDFLAGS)" -o $(DISTDIR)/$(NAME)-$(VERSION)-alpine/obp cmd/obp/*.go -################################################################################ + +debug: + $(info MD=$(MD)) + $(info WD=$(WD)) + $(info PKG=$(PKG)) + $(info PKGDIR=$(PKGDIR)) + $(info DISTDIR=$(DISTDIR)) + $(info VERSION=$(VERSION)) + $(info COMMIT_ID=$(COMMIT_ID)) + $(info BUILD_TAGS=$(BUILD_TAGS)) + $(info CMDS=$(CMDS)) + $(info BUILD_TARGETS=$(BUILD_TARGETS)) + $(info INSTALL_TARGETS=$(INSTALL_TARGETS)) diff --git a/cmd/main.go b/cmd/cli/main.go similarity index 95% rename from cmd/main.go rename to cmd/cli/main.go index d5f100e..bae4690 100644 --- a/cmd/main.go +++ b/cmd/cli/main.go @@ -5,7 +5,7 @@ import ( "fmt" "log" - "github.com/therealfakemoot/go-badge" + "code.ndumas.com/ndumas/badges" ) var ( diff --git a/cmd/web/main.go b/cmd/web/main.go new file mode 100644 index 0000000..8848771 --- /dev/null +++ b/cmd/web/main.go @@ -0,0 +1,119 @@ +package main + +import ( + "flag" + "fmt" + // "log" + "net/http" + "strconv" + + "code.ndumas.com/ndumas/badges" + "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5/middleware" +) + +var FONT_PATH = "fonts" + +type BadgeRenderer struct { + Fonts map[string]string +} + +func NewBadgeRenderer() *BadgeRenderer { + var br BadgeRenderer + br.Fonts = make(map[string]string) + + // walkfunc to find ttf files here + return &br +} + +func (br *BadgeRenderer) listFonts(w http.ResponseWriter, r *http.Request) { +} + +func (br *BadgeRenderer) renderBadge(w http.ResponseWriter, r *http.Request) { + q := r.URL.Query() + + if len(q["label"]) < 1 { + w.WriteHeader(400) + fmt.Fprintf(w, "please provide a label") + } + label := q["label"][0] + + if len(q["message"]) < 1 { + w.WriteHeader(400) + fmt.Fprintf(w, "please provide a message") + } + message := q["message"][0] + + if len(q["color"]) < 1 { + w.WriteHeader(400) + fmt.Fprintf(w, "please provide a color") + } + color := q["color"][0] + + if len(q["size"]) < 1 { + w.WriteHeader(400) + fmt.Fprintf(w, "please provide a size") + } + + size, err := strconv.ParseInt(q["size"][0], 10, 64) + if err != nil { + w.WriteHeader(400) + fmt.Fprintf(w, "could not convert size to integer: %s\n", err) + + return + } + + if len(q["font"]) < 1 { + w.WriteHeader(400) + fmt.Fprintf(w, "please provide a font name") + } + font, ok := br.Fonts[q["font"][0]] + + if !ok { + w.WriteHeader(400) + fmt.Fprintf(w, "unknown font selection\n") + } + + bg, err := badge.NewGenerator(font, int(size)) + + if err != nil { + w.WriteHeader(400) + fmt.Fprintf(w, "error instantitating generator: %s\n", err) + + return + } + + w.Header().Add("Content-Type", "image/svg+xml") + + switch q["style"][0] { + case "flat": + fmt.Fprintf(w, "%s", bg.GenerateFlat(label, message, color)) + + default: + w.WriteHeader(400) + fmt.Fprintf(w, "no matching style found\n") + } +} + +var ( + port int + fontsDir string +) + +func main() { + flag.IntVar(&port, "port", 8484, "http listening port") + flag.StringVar(&fontsDir, "fonts", "fonts/", "directory containing ttf files") + + flag.Parse() + + br := NewBadgeRenderer() + + r := chi.NewRouter() + r.Use(middleware.Logger) + // r.Use(middleware.Recoverer) + r.Use(middleware.Compress(5, "image/svg+xml")) + r.Get("/badge", br.renderBadge) + r.Get("/fonts/{format}", br.listFonts) + + http.ListenAndServe(fmt.Sprintf(":%d", port), r) +} diff --git a/go.mod b/go.mod index 013c4c5..c187152 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,10 @@ -module github.com/therealfakemoot/go-badge +module code.ndumas.com/ndumas/badges go 1.18 require ( github.com/essentialkaos/check v1.4.0 + github.com/go-chi/chi/v5 v5.0.8 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 golang.org/x/image v0.7.0 ) diff --git a/go.sum b/go.sum index 0d5b5a7..728fd0d 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/essentialkaos/check v1.4.0 h1:kWdFxu9odCxUqo1NNFNJmguGrDHgwi3A8daXX1nkuKk= github.com/essentialkaos/check v1.4.0/go.mod h1:LMKPZ2H+9PXe7Y2gEoKyVAwUqXVgx7KtgibfsHJPus0= +github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0= +github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=