Compare commits

..

5 Commits

61 changed files with 1124 additions and 520 deletions

7
.env.dist Normal file
View File

@ -0,0 +1,7 @@
COMPOSE_PROJECT_NAME=h-skills
ALPINE_VER=3.19
GOVERTER_VER=v1.4.0
GOLANGCI_LINT_VER=v1.56.2
POSTGRES_VER=16.2
AIR_VER=1.52.0
SQLC_VER=1.26.0

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/.task
/.env
/bin/env
/tmp/

2
.golangci.yml Normal file
View File

@ -0,0 +1,2 @@
# golangci-lint configuration file.
# Read more at: https://github.com/golangci/golangci-lint#config-file

20
Dockerfile Normal file
View File

@ -0,0 +1,20 @@
ARG POSTGRES_VER
ARG GO_VER
ARG ALPINE_VER
FROM postgres:${POSTGRES_VER} AS postgres
COPY ./string-unpack/internal/db/* /docker-entrypoint-initdb.d/
RUN set -ex \
&& chmod 1777 /tmp
FROM golang:${GO_VER}-alpine${ALPINE_VER} AS golang
ARG AIR_VER
RUN set -ex \
&& chmod 1777 /tmp \
&& apk add --no-cache \
git \
tzdata \
&& go install github.com/cosmtrek/air@v${AIR_VER}

129
Taskfile.go.yaml Normal file
View File

@ -0,0 +1,129 @@
version: '3'
vars:
GOFUMPT_VER: '{{.GOFUMPT_VER | default "latest"}}'
GOIMPORTS_LOCAL: '{{.GOIMPORTS_LOCAL | default nil}}'
GOIMPORT_VER: '{{.GOIMPORT_VER | default "latest"}}'
GOLANGCI_LINT_VER: '{{.GOLANGCI_LINT_VER | default "latest"}}'
GOVULNCHECK_VER: '{{.GOVULNCHECK_VER | default "latest"}}'
PROTOLINT_VER: '{{.PROTOLINT_VER | default "latest"}}'
STATICCHECK_VER: '{{.STATICCHECK_VER | default "latest"}}'
TMP_DIR: '{{.TMP_DIR | default "./tmp"}}'
tasks:
# =======
# HELPERS
# =======
lint:
desc: golangci-lint + protolint.
cmds:
- task: govulncheck
- task: staticcheck
- task: golangci-lint
- task: protolint
cs:
desc: fmt + goimports.
cmds:
- task: fmt
- task: goimports
# ===============
# QUALITY CONTROL
# ===============
fmt:
desc: format code using gofumpt.
cmds:
- >-
go run mvdan.cc/gofumpt@{{.GOFUMPT_VER}} -l -w .
sources:
- ./**/*.go
goimports:
desc: format imports using goimports.
cmds:
- >-
go run golang.org/x/tools/cmd/goimports@{{.GOIMPORT_VER}}
{{if .GOIMPORTS_LOCAL}} -local="{{.GOIMPORTS_LOCAL}}"{{end}}
-w .
sources:
- ./**/*.go
tidy:
desc: go mod tidy + go mod verify.
cmds:
- go mod tidy -v
- go mod verify
sources:
- ./**/*.go
- go.mod
- go.sum
golangci-lint:
desc: golangci-lint.
cmds:
- go run github.com/golangci/golangci-lint/cmd/golangci-lint@{{.GOLANGCI_LINT_VER}} run -v ./...
sources:
- ./**/*.go
govulncheck:
desc: govulncheck.
cmds:
- go run golang.org/x/vuln/cmd/govulncheck@{{.GOVULNCHECK_VER}} ./...
sources:
- ./**/*.go
staticcheck:
desc: staticcheck.
cmds:
- go run honnef.co/go/tools/cmd/staticcheck@{{.STATICCHECK_VER}} -checks=all,-ST1000 ./...
sources:
- ./**/*.go
protolint:
desc: protolint -fix.
cmds:
- cmd: go run github.com/yoheimuta/protolint/cmd/protolint@{{.PROTOLINT_VER}} lint -fix .
ignore_error: true
sources: &protolint_sources
- ./**/*.proto
protolint:check:
desc: protolint check.
cmds:
- go run github.com/yoheimuta/protolint/cmd/protolint@{{.PROTOLINT_VER}} lint .
sources: *protolint_sources
# ===========
# DEVELOPMENT
# ===========
generate:
desc: go generate
cmds:
- go generate ./...
sources:
- ./**/*.go
vendor:
desc: go mod vendor.
cmds:
- go mod vendor -v
sources:
- go.mod
- go.sum
generates:
- vendor
test:
desc: go tests ./...
cmds:
- go test -race -buildvcs -coverprofile={{.TMP_DIR}}/coverage.out -vet=off ./...
test:cover:
desc: tests and display coverage.
deps: [ test ]
cmds:
- go tool cover -html={{.TMP_DIR}}/coverage.out

192
Taskfile.yaml Normal file
View File

@ -0,0 +1,192 @@
version: '3'
includes:
go:
taskfile: ./Taskfile.go.yaml
output: prefixed
silent: true
interval: 1s
dotenv:
- ./.env
vars:
NEWLINE_EXCLUDE: >-
-not -path "./.git/*"
-not -path "./.idea/*"
-not -path "./vendor/*"
-not -path "./tmp/*"
-not -name "*.ico"
-not -name "*.png"
-not -name "*.svg"
tasks:
# =======
# HELPERS
# =======
all:
desc: generate + tidy + lint + test.
cmds:
- task: generate
- task: go:tidy
- task: go:lint
- task: go:test
generate:
desc: all generators + cs.
cmds:
- task: sqlc
- task: goverter
- task: go:generate
- task: cs
cs:
desc: go:cs + newline.
cmds:
- task: go:cs
- task: newline
# ===============
# QUALITY CONTROL
# ===============
newline:
desc: add newline at end file.
cmds:
- >-
find .
{{.NEWLINE_EXCLUDE}}
-type f -exec grep -Iq . {} \; -and -print0
| xargs -0 -n 1 sh -c 'test -z "$(tail -c 1 "$0")"
|| (echo "" >> $0 && echo $0)'
|| exit 1
sources: &newline_sources
- ./**/*
- exclude: "*.ico"
- exclude: "*.png"
- exclude: "*.svg"
newline:check:
desc: check newline at end file.
cmds:
- find .
{{.NEWLINE_EXCLUDE}}
-type f -exec grep -Iq . {} \; -and -print0
| xargs -0 -n 1 sh -c 'test -z "$(tail -c 1 "$0")"
|| (echo "No new line at end of $0" && exit 1)'
|| exit 1
sources: *newline_sources
# ===========
# DEVELOPMENT
# ===========
dotenv:install:
internal: true
cmds:
- mkdir -p bin
- curl -o bin/env https://raw.githubusercontent.com/bashup/dotenv/master/dotenv
- chmod +x bin/env
status:
- test -f bin/env
dotenv:
deps: [ dotenv:install ]
desc: fill .env file.
vars:
UID:
sh: id -u
GID:
sh: id -g
GO_VER:
sh: go mod edit -json | jq -r .Go
GOIMPORTS_LOCAL:
sh: go list -m | awk -F/ '{print $1}'
ENV_DIST:
sh: cat .env.dist|tr '\n' ' '
GOPATH:
sh: go env GOPATH
cmds:
- bin/env set GROUP_ID={{.UID}} USER_ID={{.GID}} GO_VER={{.GO_VER}} GOPATH={{.GOPATH}} {{.ENV_DIST}}
sources:
- .env.dist
- Taskfile.yaml
generates:
- .env
goverter:
desc: go run goverter
deps: [ dotenv ]
cmds:
- go run github.com/jmattheis/goverter/cmd/goverter@{{.GOVERTER_VER}} gen ./...
sources:
- ./**/*.go
sqlc:
desc: go run sqlc.
deps: [ dotenv ]
cmds:
- go run github.com/sqlc-dev/sqlc/cmd/sqlc@v{{.SQLC_VER}} generate
sources:
- sqlc.yaml
- ./**/sql/**/*
- ./**/db/**/*
# =========
# OPERATION
# =========
up:
desc: up all services.
cmds:
- task: postgres:up
- task: api:up
down:
desc: docker compose down.
deps: [ dotenv ]
cmds:
- docker compose down -v --remove-orphans
postgres:build:
internal: true
desc: docker compose build postgres.
deps: [ dotenv ]
cmds:
- docker compose build postgres
sources:
- ./**/db/**/*
- Dockerfile
- docker-compose.yml
postgres:up:
desc: docker compose up postgres.
deps: [ dotenv, postgres:build ]
cmds:
- docker compose up -d --force-recreate postgres
postgres:push:
desc: docker compose push postgres.
deps: [ dotenv, postgres:build ]
cmds:
- docker compose push postgres
api:build:
internal: true
desc: docker compose build api image.
deps: [ dotenv ]
cmds:
- docker compose build api
sources:
- .env
- Dockerfile
- docker-compose.yml
api:up:
desc: docker compose up api.
deps: [ dotenv, api:build ]
cmds:
- docker compose up -d --force-recreate api

24
cmd/api/config.go Normal file
View File

@ -0,0 +1,24 @@
package main
import (
"flag"
"time"
"github.com/kelseyhightower/envconfig"
)
type Config struct {
DSN string `envconfig:"DSN" default:"postgresql://postgres:postgres@postgres:5432/postgres?sslmode=disable"`
ReconnectTimeout time.Duration `envconfig:"RECONNECT_TIMEOUT" default:"2s"`
}
func (c *Config) Parse() error {
flag.StringVar(&c.DSN, "DSN", "", "postgresql DSN")
flag.Parse()
if err := envconfig.Process("", c); err != nil {
return err
}
return nil
}

113
cmd/api/main.go Normal file
View File

@ -0,0 +1,113 @@
package main
import (
"context"
"errors"
"net/http"
"os/signal"
"syscall"
"time"
"github.com/jackc/pgx/v5"
stringunpack "git.grachevko.ru/grachevko/h/string-unpack"
"github.com/gin-gonic/gin"
"github.com/prometheus/client_golang/prometheus"
collector "github.com/prometheus/client_golang/prometheus/collectors/version"
"github.com/prometheus/client_golang/prometheus/promhttp"
"go.uber.org/zap"
"golang.org/x/sync/errgroup"
)
func main() {
logger, _ := zap.NewProduction()
defer func(logger *zap.Logger) {
_ = logger.Sync()
}(logger) // flushes buffer, if any
cfg := Config{}
if err := cfg.Parse(); err != nil {
logger.Fatal("config parse", zap.Error(err))
}
ctx := context.Background()
ctx, stop := signal.NotifyContext(ctx, syscall.SIGINT, syscall.SIGTERM)
defer stop()
var metricServer *http.Server
{ // Metrics
prometheus.MustRegister(collector.NewCollector("unpack"))
mux := http.NewServeMux()
mux.Handle("/metrics", promhttp.Handler())
metricServer = &http.Server{
Handler: mux,
Addr: ":8089",
}
go func() {
if err := metricServer.ListenAndServe(); err != nil {
logger.Error("metric server failed", zap.Error(err))
}
}()
} // Metrics
pgconn:
conn, err := pgx.Connect(ctx, cfg.DSN)
if err != nil {
logger.Error("pgx", zap.Error(err))
logger.Info("Wait before reconnect", zap.Duration("after", cfg.ReconnectTimeout))
<-time.After(cfg.ReconnectTimeout)
logger.Info("Retrying connection")
goto pgconn
}
defer func(conn *pgx.Conn, ctx context.Context) {
if err = conn.Close(ctx); err != nil {
logger.Error("pgx close", zap.Error(err))
}
}(conn, ctx)
var httpServer *http.Server
{ // Http
r := gin.Default()
stringunpack.Setup(ctx, logger, r.Group("unpack"), conn)
httpServer = &http.Server{
Addr: ":8080",
Handler: r,
}
go func() {
if err := httpServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
logger.Error("http server failed", zap.Error(err))
}
}()
} // Http
// Listen for the interrupt signal.
<-ctx.Done()
{ // Graceful shutdown
// Restore default behavior on the interrupt signal and notify user of shutdown.
stop()
logger.Info("shutting down gracefully, press Ctrl+C again to force")
// The context is used to inform the server it has 5 seconds to finish
// the request it is currently handling
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
g, ctx := errgroup.WithContext(ctx)
g.Go(func() error { return metricServer.Shutdown(ctx) })
g.Go(func() error { return httpServer.Shutdown(ctx) })
if err := g.Wait(); err != nil {
logger.Error("graceful shutdown failed", zap.Error(err))
}
} // Graceful shutdown
logger.Info("Server exiting")
}

View File

@ -2,8 +2,6 @@ package main
import "flag" import "flag"
const stdin = "-"
type Config struct { type Config struct {
Key int Key int
Numeric bool Numeric bool
@ -23,6 +21,6 @@ func (c *Config) ParseFlags() {
c.Sources = flag.Args() c.Sources = flag.Args()
if len(c.Sources) == 0 { if len(c.Sources) == 0 {
c.Sources = []string{stdin} c.Sources = []string{"-"}
} }
} }

View File

@ -2,6 +2,8 @@ package main
import ( import (
"os" "os"
sortcli "git.grachevko.ru/grachevko/h/sort-cli"
) )
func main() { func main() {
@ -18,8 +20,8 @@ func run() string {
cfg := &Config{} cfg := &Config{}
cfg.ParseFlags() cfg.ParseFlags()
lines := content{} lines := sortcli.Content{}
lines.Load(open(cfg.Sources)) lines.Load(sortcli.Open(cfg.Sources))
if cfg.Unique { if cfg.Unique {
lines.Uniques() lines.Uniques()

View File

@ -2,10 +2,11 @@ package main
import ( import (
"flag" "flag"
"github.com/stretchr/testify/assert"
"os" "os"
"strings" "strings"
"testing" "testing"
"github.com/stretchr/testify/assert"
) )
func TestFlags(t *testing.T) { func TestFlags(t *testing.T) {
@ -20,22 +21,26 @@ func TestFlags(t *testing.T) {
ExpectedExit int ExpectedExit int
ExpectedOutput string ExpectedOutput string
}{ }{
{"No flags", {
"No flags",
[]string{"testdata/first"}, []string{"testdata/first"},
0, 0,
"alabama barcelona\nbarcelona california\ncalifornia denver\ncalifornia denver\nамур брянск\nбелгород волгоград\nволгоград геленджик", "alabama barcelona\nbarcelona california\ncalifornia denver\ncalifornia denver\nамур брянск\nбелгород волгоград\nволгоград геленджик",
}, },
{"Reverse", {
"Reverse",
[]string{"-r", "testdata/first"}, []string{"-r", "testdata/first"},
0, 0,
"волгоград геленджик\nбелгород волгоград\nамур брянск\ncalifornia denver\ncalifornia denver\nbarcelona california\nalabama barcelona", "волгоград геленджик\nбелгород волгоград\nамур брянск\ncalifornia denver\ncalifornia denver\nbarcelona california\nalabama barcelona",
}, },
{"Unique", {
"Unique",
[]string{"-u", "testdata/first"}, []string{"-u", "testdata/first"},
0, 0,
"alabama barcelona\nbarcelona california\ncalifornia denver\nамур брянск\nбелгород волгоград\nволгоград геленджик", "alabama barcelona\nbarcelona california\ncalifornia denver\nамур брянск\nбелгород волгоград\nволгоград геленджик",
}, },
{"Column 2", {
"Column 2",
[]string{"-k=2", "testdata/first"}, []string{"-k=2", "testdata/first"},
0, 0,
"alabama barcelona\nbarcelona california\ncalifornia denver\ncalifornia denver\nамур брянск\nбелгород волгоград\nволгоград геленджик", "alabama barcelona\nbarcelona california\ncalifornia denver\ncalifornia denver\nамур брянск\nбелгород волгоград\nволгоград геленджик",

41
docker-compose.yml Normal file
View File

@ -0,0 +1,41 @@
services:
postgres:
build:
target: postgres
context: .
args: &args
AIR_VER: ${AIR_VER}
ALPINE_VER: ${ALPINE_VER}
GO_VER: ${GO_VER}
POSTGRES_VER: ${POSTGRES_VER}
image: harbor.grachevko.ru/grachevko/h-skills/postgres:dev
labels:
ru.grachevko.dhu: 'postgres.h-skills.local'
environment:
POSTGRES_DB: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
PGDATABASE: postgres
PGUSER: postgres
PGPASSWORD: postgres
volumes:
- type: tmpfs
target: /var/lib/postgresql/data
tmpfs:
size: 4294967296
api:
build:
target: golang
args: *args
command: air --build.cmd "go build -o ./tmp/api ./cmd/api/" --build.bin "./tmp/api"
labels:
ru.grachevko.dhu: 'api.h-skills.local'
environment:
GOPATH: ${GOPATH}
working_dir: /app
volumes:
- ./:/app
- ${GOPATH}:${GOPATH}
- ${HOME}/.cache/go-build:/.cache/go-build
user: ${USER_ID}:${GROUP_ID}

53
go.mod Normal file
View File

@ -0,0 +1,53 @@
module git.grachevko.ru/grachevko/h
go 1.22.3
require (
github.com/gin-gonic/gin v1.10.0
github.com/jackc/pgx/v5 v5.5.5
github.com/kelseyhightower/envconfig v1.4.0
github.com/prometheus/client_golang v1.19.0
github.com/stretchr/testify v1.9.0
go.uber.org/zap v1.27.0
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
golang.org/x/sync v0.7.0
)
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/bytedance/sonic v1.11.6 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.20.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.6.0 // indirect
github.com/prometheus/common v0.53.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
go.uber.org/multierr v1.10.0 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
google.golang.org/protobuf v1.34.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

126
go.sum Normal file
View File

@ -0,0 +1,126 @@
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos=
github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8=
github.com/prometheus/common v0.53.0 h1:U2pL9w9nmJwJDa4qqLQ3ZaePJ6ZTwt7cMD3AG3+aLCE=
github.com/prometheus/common v0.53.0/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

View File

@ -1,48 +0,0 @@
.DEFAULT_GOAL := help
# ==================================================================================== #
# HELPERS
# ==================================================================================== #
## help: print this help message
.PHONY: help
help:
@echo 'Usage:'
@sed -n 's/^##//p' ${MAKEFILE_LIST} | column -t -s ':' | sed -e 's/^/ /'
# ==================================================================================== #
# QUALITY CONTROL
# ==================================================================================== #
## tidy: format code and tidy modfile
.PHONY: tidy
tidy:
go fmt ./...
go mod tidy -v
## audit: run quality control checks
.PHONY: audit
audit:
go mod verify
go vet ./...
go run honnef.co/go/tools/cmd/staticcheck@latest -checks=all,-ST1000,-U1000 ./...
go run golang.org/x/vuln/cmd/govulncheck@latest ./...
go test -race -buildvcs -vet=off ./...
go run github.com/golangci/golangci-lint/cmd/golangci-lint@latest run -v ./...
# ==================================================================================== #
# DEVELOPMENT
# ==================================================================================== #
## test: run all tests
.PHONY: test
test:
go test -v -race -buildvcs ./...
## test/cover: run all tests and display coverage
.PHONY: test/cover
test/cover:
go test -v -race -buildvcs -coverprofile=/tmp/coverage.out ./...
go tool cover -html=/tmp/coverage.out

View File

@ -1,11 +0,0 @@
module lru
go 1.21.6
require github.com/stretchr/testify v1.8.4
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@ -1,10 +0,0 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -2,9 +2,10 @@ package lru
import ( import (
"fmt" "fmt"
"github.com/stretchr/testify/assert"
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/assert"
) )
func TestTtl(t *testing.T) { func TestTtl(t *testing.T) {

View File

@ -1,53 +0,0 @@
.DEFAULT_GOAL := help
# ==================================================================================== #
# HELPERS
# ==================================================================================== #
## help: print this help message
.PHONY: help
help:
@echo 'Usage:'
@sed -n 's/^##//p' ${MAKEFILE_LIST} | column -t -s ':' | sed -e 's/^/ /'
## all: tidy + audit + test/cover
all: generate tidy test lint test/cover
# ==================================================================================== #
# QUALITY CONTROL
# ==================================================================================== #
## tidy: format code and tidy modfile
.PHONY: tidy
tidy:
go fmt ./...
goimports -local=$(shell cat go.mod | grep module | awk '{print $$2}')/ -w .
go mod tidy -v
## audit: run quality control checks
.PHONY: lint
lint:
go mod verify
go run github.com/golangci/golangci-lint/cmd/golangci-lint@latest run -v ./...
# ==================================================================================== #
# DEVELOPMENT
# ==================================================================================== #
## generate: run all generators
.PHONY: generate
generate:
go generate ./...
## test: run all tests
.PHONY: test
test:
go test -race -buildvcs ./...
## test/cover: run all tests and display coverage
.PHONY: test/cover
test/cover:
go test -race -buildvcs -coverprofile=/tmp/coverage.out ./...
go tool cover -html=/tmp/coverage.out

View File

@ -1,11 +0,0 @@
module merge-channel
go 1.21.6
require github.com/stretchr/testify v1.8.4
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@ -1,10 +0,0 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -1,11 +1,11 @@
package main package mergechannel
import ( import (
"errors" "errors"
"sync" "sync"
) )
var InsufficientChannelsErr = errors.New("channels count must be >2") var ErrInsufficientChannels = errors.New("channels count must be >2")
func merge[T any](channels ...<-chan T) (<-chan T, error) { func merge[T any](channels ...<-chan T) (<-chan T, error) {
out := make(chan T) out := make(chan T)
@ -13,7 +13,7 @@ func merge[T any](channels ...<-chan T) (<-chan T, error) {
if len(channels) < 2 { if len(channels) < 2 {
close(out) close(out)
return out, InsufficientChannelsErr return out, ErrInsufficientChannels
} }
var wg sync.WaitGroup var wg sync.WaitGroup

View File

@ -1,4 +1,4 @@
package main package mergechannel
import ( import (
"testing" "testing"
@ -32,5 +32,5 @@ func TestInsufficient(t *testing.T) {
a := make(chan int) a := make(chan int)
_, err := merge(a) _, err := merge(a)
assert.Equal(t, err, InsufficientChannelsErr) assert.Equal(t, err, ErrInsufficientChannels)
} }

View File

@ -1,53 +0,0 @@
.DEFAULT_GOAL := help
# ==================================================================================== #
# HELPERS
# ==================================================================================== #
## help: print this help message
.PHONY: help
help:
@echo 'Usage:'
@sed -n 's/^##//p' ${MAKEFILE_LIST} | column -t -s ':' | sed -e 's/^/ /'
## all: tidy + audit + test/cover
all: generate tidy test lint test/cover
# ==================================================================================== #
# QUALITY CONTROL
# ==================================================================================== #
## tidy: format code and tidy modfile
.PHONY: tidy
tidy:
go fmt ./...
goimports -local=$(shell cat go.mod | grep module | awk '{print $$2}')/ -w .
go mod tidy -v
## audit: run quality control checks
.PHONY: lint
lint:
go mod verify
go run github.com/golangci/golangci-lint/cmd/golangci-lint@latest run -v ./...
# ==================================================================================== #
# DEVELOPMENT
# ==================================================================================== #
## generate: run all generators
.PHONY: generate
generate:
go generate ./...
## test: run all tests
.PHONY: test
test:
go test -race -buildvcs ./...
## test/cover: run all tests and display coverage
.PHONY: test/cover
test/cover:
go test -race -buildvcs -coverprofile=/tmp/coverage.out ./...
go tool cover -html=/tmp/coverage.out

View File

@ -1,11 +0,0 @@
module pipeline
go 1.21.6
require github.com/stretchr/testify v1.8.4
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@ -1,10 +0,0 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -1,4 +1,4 @@
package main package pipeline
func Pipe[In any, Out any](in <-chan In, pipe func(In) Out) <-chan Out { func Pipe[In any, Out any](in <-chan In, pipe func(In) Out) <-chan Out {
out := make(chan Out) out := make(chan Out)

View File

@ -1,4 +1,4 @@
package main package pipeline
import ( import (
"testing" "testing"

View File

@ -1,53 +0,0 @@
.DEFAULT_GOAL := help
# ==================================================================================== #
# HELPERS
# ==================================================================================== #
## help: print this help message
.PHONY: help
help:
@echo 'Usage:'
@sed -n 's/^##//p' ${MAKEFILE_LIST} | column -t -s ':' | sed -e 's/^/ /'
## all: tidy + audit + test/cover
all: generate tidy test lint test/cover
# ==================================================================================== #
# QUALITY CONTROL
# ==================================================================================== #
## tidy: format code and tidy modfile
.PHONY: tidy
tidy:
go fmt ./...
goimports -local=$(shell cat go.mod | grep module | awk '{print $$2}')/ -w .
go mod tidy -v
## audit: run quality control checks
.PHONY: lint
lint:
go mod verify
go run github.com/golangci/golangci-lint/cmd/golangci-lint@latest run -v ./...
# ==================================================================================== #
# DEVELOPMENT
# ==================================================================================== #
## generate: run all generators
.PHONY: generate
generate:
go generate ./...
## test: run all tests
.PHONY: test
test:
go test -race -buildvcs ./...
## test/cover: run all tests and display coverage
.PHONY: test/cover
test/cover:
go test -race -buildvcs -coverprofile=/tmp/coverage.out ./...
go tool cover -html=/tmp/coverage.out

View File

@ -1,3 +0,0 @@
module semaphore
go 1.21.6

View File

@ -1,4 +1,4 @@
package main package semaphore
import ( import (
"context" "context"

View File

@ -1,9 +1,8 @@
package main package semaphore
import ( import (
"testing" "testing"
) )
func TestPipe(t *testing.T) { func TestPipe(t *testing.T) {
} }

View File

@ -1,50 +0,0 @@
.DEFAULT_GOAL := help
# ==================================================================================== #
# HELPERS
# ==================================================================================== #
## help: print this help message
.PHONY: help
help:
@echo 'Usage:'
@sed -n 's/^##//p' ${MAKEFILE_LIST} | column -t -s ':' | sed -e 's/^/ /'
## all: tidy + audit + test/cover
all: tidy audit test/cover
# ==================================================================================== #
# QUALITY CONTROL
# ==================================================================================== #
## tidy: format code and tidy modfile
.PHONY: tidy
tidy:
go fmt ./...
go mod tidy -v
## audit: run quality control checks
.PHONY: audit
audit:
go mod verify
go vet ./...
go run honnef.co/go/tools/cmd/staticcheck@latest -checks=all,-ST1000,-U1000 ./...
go run golang.org/x/vuln/cmd/govulncheck@latest ./...
go test -race -buildvcs -vet=off ./...
go run github.com/golangci/golangci-lint/cmd/golangci-lint@latest run -v ./...
# ==================================================================================== #
# DEVELOPMENT
# ==================================================================================== #
## test: run all tests
.PHONY: test
test:
go test -v -race -buildvcs ./...
## test/cover: run all tests and display coverage
.PHONY: test/cover
test/cover:
go test -v -race -buildvcs -coverprofile=/tmp/coverage.out ./...
go tool cover -html=/tmp/coverage.out

View File

@ -1,20 +1,21 @@
package main package sortcli
import ( import (
"bufio" "bufio"
"errors" "errors"
"golang.org/x/exp/slices"
"io" "io"
"log" "log"
"strings" "strings"
"golang.org/x/exp/slices"
) )
// NL New line constant // NL New line constant
const NL = "\n" const NL = "\n"
type content [][]byte type Content [][]byte
func (c *content) Sort(reverse bool) { func (c *Content) Sort(reverse bool) {
slices.SortFunc(*c, func(a, b []byte) int { slices.SortFunc(*c, func(a, b []byte) int {
if reverse { if reverse {
a, b = b, a a, b = b, a
@ -24,10 +25,10 @@ func (c *content) Sort(reverse bool) {
}) })
} }
func (c *content) Uniques() { func (c *Content) Uniques() {
m := make(map[string]struct{}, len(*c)) m := make(map[string]struct{}, len(*c))
*c = slices.DeleteFunc[content, []byte](*c, func(line []byte) bool { *c = slices.DeleteFunc[Content, []byte](*c, func(line []byte) bool {
if _, ok := m[string(line)]; !ok { if _, ok := m[string(line)]; !ok {
m[string(line)] = struct{}{} m[string(line)] = struct{}{}
@ -38,7 +39,7 @@ func (c *content) Uniques() {
}) })
} }
func (c *content) String() string { func (c *Content) String() string {
lines := *c lines := *c
var n int var n int
@ -63,7 +64,7 @@ func (c *content) String() string {
return sb.String() return sb.String()
} }
func (c *content) Load(r io.Reader) { func (c *Content) Load(r io.Reader) {
br := bufio.NewReader(r) br := bufio.NewReader(r)
for { for {

View File

@ -1,9 +1,10 @@
package main package sortcli
import ( import (
"github.com/stretchr/testify/assert"
"strings" "strings"
"testing" "testing"
"github.com/stretchr/testify/assert"
) )
const input = ` const input = `
@ -15,7 +16,7 @@ Africa
` `
func TestLoad(t *testing.T) { func TestLoad(t *testing.T) {
c := &content{} c := &Content{}
c.Load(strings.NewReader(input)) c.Load(strings.NewReader(input))
assert.Equal(t, input, c.String()) assert.Equal(t, input, c.String())
@ -27,7 +28,8 @@ func TestUnique(t *testing.T) {
Content string Content string
Expected string Expected string
}{ }{
{"Unique", {
"Unique",
input, input,
` `
Zimbabwe Zimbabwe
@ -40,7 +42,7 @@ America`,
tc := tc tc := tc
t.Run(tc.Name, func(t *testing.T) { t.Run(tc.Name, func(t *testing.T) {
c := &content{} c := &Content{}
c.Load(strings.NewReader(tc.Content)) c.Load(strings.NewReader(tc.Content))
c.Uniques() c.Uniques()

View File

@ -1,14 +0,0 @@
module sort-cli
go 1.21.6
require (
github.com/stretchr/testify v1.8.4
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3
)
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@ -1,12 +0,0 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 h1:hNQpMuAJe5CtcUqCXaWga3FHu+kQvCqcsoVaQgSV60o=
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -1,4 +1,4 @@
package main package sortcli
import ( import (
"io" "io"
@ -6,13 +6,13 @@ import (
"os" "os"
) )
func open(sources []string) io.Reader { func Open(sources []string) io.Reader {
rs := make([]io.Reader, 0, len(sources)) rs := make([]io.Reader, 0, len(sources))
for _, source := range sources { for _, source := range sources {
var r io.Reader var r io.Reader
if source == stdin { if source == "-" {
r = os.Stdin r = os.Stdin
} else { } else {
if _, err := os.Stat(source); err != nil { if _, err := os.Stat(source); err != nil {

14
sqlc.yaml Normal file
View File

@ -0,0 +1,14 @@
version: "2"
sql:
- engine: "postgresql"
queries: "string-unpack/internal/sql/"
schema: "string-unpack/internal/db/schema.sql"
gen:
go:
out: "string-unpack/internal/sql"
sql_package: "pgx/v5"
emit_db_tags: true
emit_interface: true
emit_json_tags: true
emit_methods_with_db_argument: false
query_parameter_limit: 0

View File

@ -0,0 +1,10 @@
CREATE EXTENSION IF NOT EXISTS pgcrypto;
CREATE TABLE unpack_history
(
id uuid default gen_random_uuid() primary key,
input text NOT NULL,
result text NOT NULL,
created_at timestamptz DEFAULT NOW()
)
;

View File

@ -0,0 +1,32 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.26.0
package sql
import (
"context"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgconn"
)
type DBTX interface {
Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error)
Query(context.Context, string, ...interface{}) (pgx.Rows, error)
QueryRow(context.Context, string, ...interface{}) pgx.Row
}
func New(db DBTX) *Queries {
return &Queries{db: db}
}
type Queries struct {
db DBTX
}
func (q *Queries) WithTx(tx pgx.Tx) *Queries {
return &Queries{
db: tx,
}
}

View File

@ -0,0 +1,9 @@
-- name: Insert :one
INSERT INTO unpack_history (input, result)
VALUES (@input, @result)
RETURNING
id,
input,
result,
created_at
;

View File

@ -0,0 +1,37 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.26.0
// source: insert.sql
package sql
import (
"context"
)
const insert = `-- name: Insert :one
INSERT INTO unpack_history (input, result)
VALUES ($1, $2)
RETURNING
id,
input,
result,
created_at
`
type InsertParams struct {
Input string `db:"input" json:"input"`
Result string `db:"result" json:"result"`
}
func (q *Queries) Insert(ctx context.Context, arg InsertParams) (UnpackHistory, error) {
row := q.db.QueryRow(ctx, insert, arg.Input, arg.Result)
var i UnpackHistory
err := row.Scan(
&i.ID,
&i.Input,
&i.Result,
&i.CreatedAt,
)
return i, err
}

View File

@ -0,0 +1,9 @@
-- name: Latest :many
SELECT id,
input,
result,
created_at
FROM unpack_history
ORDER BY created_at DESC
LIMIT 15
;

View File

@ -0,0 +1,45 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.26.0
// source: latest.sql
package sql
import (
"context"
)
const latest = `-- name: Latest :many
SELECT id,
input,
result,
created_at
FROM unpack_history
ORDER BY created_at DESC
LIMIT 15
`
func (q *Queries) Latest(ctx context.Context) ([]UnpackHistory, error) {
rows, err := q.db.Query(ctx, latest)
if err != nil {
return nil, err
}
defer rows.Close()
var items []UnpackHistory
for rows.Next() {
var i UnpackHistory
if err := rows.Scan(
&i.ID,
&i.Input,
&i.Result,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}

View File

@ -0,0 +1,16 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.26.0
package sql
import (
"github.com/jackc/pgx/v5/pgtype"
)
type UnpackHistory struct {
ID pgtype.UUID `db:"id" json:"id"`
Input string `db:"input" json:"input"`
Result string `db:"result" json:"result"`
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
}

View File

@ -0,0 +1,16 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.26.0
package sql
import (
"context"
)
type Querier interface {
Insert(ctx context.Context, arg InsertParams) (UnpackHistory, error)
Latest(ctx context.Context) ([]UnpackHistory, error)
}
var _ Querier = (*Queries)(nil)

78
string-unpack/server.go Normal file
View File

@ -0,0 +1,78 @@
package stringunpack
import (
"context"
"errors"
"fmt"
"net/http"
"git.grachevko.ru/grachevko/h/string-unpack/internal/sql"
"github.com/gin-gonic/gin"
"github.com/jackc/pgx/v5"
"go.uber.org/zap"
)
var queries sql.Querier
func Setup(ctx context.Context, logger *zap.Logger, r *gin.RouterGroup, conn *pgx.Conn) {
if queries != nil {
panic("Setup must call only once")
}
queries = sql.New(conn)
unpack := func(input string) (r string, err error) {
r, err = Unpack(input)
{ // history
result := r
if err != nil {
result = fmt.Sprintf("err: %s", err.Error())
}
_, err := queries.Insert(ctx, sql.InsertParams{
Input: input,
Result: result,
})
if err != nil {
logger.Error("pg insert", zap.Error(err))
}
} // history
return
}
r.GET("history", func(c *gin.Context) {
latest, err := queries.Latest(ctx)
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{
"err": err.Error(),
})
return
}
c.JSON(http.StatusOK, latest)
})
r.GET(":s", func(c *gin.Context) {
s := c.Param("s")
result, err := unpack(s)
if errors.Is(err, ErrIncorrectString) {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{
"err": err.Error(),
})
return
}
if err != nil {
logger.Error("unpack", zap.Error(err))
c.AbortWithStatus(http.StatusInternalServerError)
}
c.JSON(http.StatusOK, gin.H{
"result": result,
})
})
}

54
string-unpack/unpack.go Normal file
View File

@ -0,0 +1,54 @@
package stringunpack
import (
"errors"
"strconv"
"strings"
)
var ErrIncorrectString = errors.New("incorrect string")
func Unpack(s string) (string, error) {
if s == "" {
return "", nil
}
var sb strings.Builder
sb.Grow(len(s))
var curSymbol rune
for _, r := range s {
isNumber := false
number := 0
if n, err := strconv.Atoi(string(r)); err == nil {
number = n
isNumber = true
}
if curSymbol == rune(0) {
switch {
case isNumber:
return "", ErrIncorrectString
case !isNumber:
curSymbol = r
}
} else {
switch {
case !isNumber:
sb.WriteRune(curSymbol)
curSymbol = r
case isNumber:
for i := 0; i < number; i++ {
sb.WriteRune(curSymbol)
}
curSymbol = rune(0)
}
}
}
if curSymbol != rune(0) {
sb.WriteRune(curSymbol)
}
return sb.String(), nil
}

View File

@ -0,0 +1,44 @@
package stringunpack_test
import (
"testing"
stringunpack "git.grachevko.ru/grachevko/h/string-unpack"
"github.com/stretchr/testify/assert"
)
func TestUnpack(t *testing.T) {
testcases := []struct {
input string
expected string
}{
{input: "a4bc2d5e", expected: "aaaabccddddde"},
{input: "abcd", expected: "abcd"},
{input: "aaa0b", expected: "aab"},
{input: "", expected: ""},
{input: "d\n5abc", expected: "d\n\n\n\n\nabc"},
}
for _, tc := range testcases {
t.Run(tc.input, func(t *testing.T) {
result, err := stringunpack.Unpack(tc.input)
assert.NoError(t, err)
assert.Equal(t, tc.expected, result)
})
}
}
func TestUnpackIncorrectString(t *testing.T) {
testcases := []string{
"3abc",
"45",
"aaa10b",
}
for _, input := range testcases {
t.Run(input, func(t *testing.T) {
_, err := stringunpack.Unpack(input)
assert.Equal(t, stringunpack.ErrIncorrectString, err)
})
}
}

0
tmp/.gitkeep Normal file
View File

View File

@ -1,48 +0,0 @@
.DEFAULT_GOAL := help
# ==================================================================================== #
# HELPERS
# ==================================================================================== #
## help: print this help message
.PHONY: help
help:
@echo 'Usage:'
@sed -n 's/^##//p' ${MAKEFILE_LIST} | column -t -s ':' | sed -e 's/^/ /'
# ==================================================================================== #
# QUALITY CONTROL
# ==================================================================================== #
## tidy: format code and tidy modfile
.PHONY: tidy
tidy:
go fmt ./...
go mod tidy -v
## audit: run quality control checks
.PHONY: audit
audit:
go mod verify
go vet ./...
go run honnef.co/go/tools/cmd/staticcheck@latest -checks=all,-ST1000,-U1000 ./...
go run golang.org/x/vuln/cmd/govulncheck@latest ./...
go test -race -buildvcs -vet=off ./...
go run github.com/golangci/golangci-lint/cmd/golangci-lint@latest run -v ./...
# ==================================================================================== #
# DEVELOPMENT
# ==================================================================================== #
## test: run all tests
.PHONY: test
test:
go test -v -race -buildvcs ./...
## test/cover: run all tests and display coverage
.PHONY: test/cover
test/cover:
go test -v -race -buildvcs -coverprofile=/tmp/coverage.out ./...
go tool cover -html=/tmp/coverage.out

View File

@ -1,10 +0,0 @@
module uniqueschars
go 1.21.6
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/testify v1.8.4 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@ -1,9 +0,0 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -1,8 +1,9 @@
package uniqueschars package uniqueschars
import ( import (
"github.com/stretchr/testify/assert"
"testing" "testing"
"github.com/stretchr/testify/assert"
) )
func TestUnique(t *testing.T) { func TestUnique(t *testing.T) {

View File

@ -1,53 +0,0 @@
.DEFAULT_GOAL := help
# ==================================================================================== #
# HELPERS
# ==================================================================================== #
## help: print this help message
.PHONY: help
help:
@echo 'Usage:'
@sed -n 's/^##//p' ${MAKEFILE_LIST} | column -t -s ':' | sed -e 's/^/ /'
## all: tidy + audit + test/cover
all: generate tidy test lint test/cover
# ==================================================================================== #
# QUALITY CONTROL
# ==================================================================================== #
## tidy: format code and tidy modfile
.PHONY: tidy
tidy:
go fmt ./...
goimports -local=$(shell cat go.mod | grep module | awk '{print $$2}')/ -w .
go mod tidy -v
## audit: run quality control checks
.PHONY: lint
lint:
go mod verify
go run github.com/golangci/golangci-lint/cmd/golangci-lint@latest run -v ./...
# ==================================================================================== #
# DEVELOPMENT
# ==================================================================================== #
## generate: run all generators
.PHONY: generate
generate:
go generate ./...
## test: run all tests
.PHONY: test
test:
go test -race -buildvcs ./...
## test/cover: run all tests and display coverage
.PHONY: test/cover
test/cover:
go test -race -buildvcs -coverprofile=/tmp/coverage.out ./...
go tool cover -html=/tmp/coverage.out

View File

@ -1,11 +0,0 @@
module worker-pool
go 1.21.6
require github.com/stretchr/testify v1.8.4
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@ -1,4 +1,4 @@
package main package workerpool
import ( import (
"fmt" "fmt"

View File

@ -1,4 +1,4 @@
package main package workerpool
import ( import (
"fmt" "fmt"