Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
eyudkin committed Dec 7, 2020
0 parents commit d84b83b
Show file tree
Hide file tree
Showing 22 changed files with 1,784 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.idea
599 changes: 599 additions & 0 deletions README.md

Large diffs are not rendered by default.

210 changes: 210 additions & 0 deletions README.tpl

Large diffs are not rendered by default.

157 changes: 157 additions & 0 deletions cmd/gen.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
// Generates a README.md from the README.tpl and provides some template helpers.
package main

import (
"fmt"
"go/ast"
"go/parser"
"go/token"
"io/ioutil"
"os"
"strings"
"text/template"
"unicode"
"unicode/utf8"
)

func main() {
if err := run(); err != nil {
println(err.Error())
os.Exit(1)
}
}

func run() error {
const tplName = "README.tpl"
tplVal, err := ioutil.ReadFile(tplName)
if err != nil {
return fmt.Errorf("can't read a file %q: %w", tplName, err)
}

tpl := template.New("readme").Funcs(template.FuncMap{
"quote_go_func": func(fileName, funcName string) (string, error) {
fileVal, err := ioutil.ReadFile(fileName)
if err != nil {
return "", fmt.Errorf("can't read a file %q: %w", fileName, err)
}

fileValS := string(fileVal)
f, err := parser.ParseFile(token.NewFileSet(), fileName, fileValS, 0)
if err != nil {
return "", fmt.Errorf("can't parse a file %q: %w", fileName, err)
}
found := false
var functionBody string
ast.Inspect(f, func(node ast.Node) bool {
if found {
return false
}
fDecl, ok := node.(*ast.FuncDecl)
if ok && fDecl.Name.Name == funcName && fDecl.Body != nil {
found = true
functionBody = fileValS[fDecl.Pos()-1 : fDecl.End()]
return false
}

return true
})

if !found {
return "", fmt.Errorf("can't read a file %q: %w", fileName, err)
}

return resetIndents(functionBody), nil
},
"quote_go_func_body": func(fileName, funcName string) (string, error) {
fileVal, err := ioutil.ReadFile(fileName)
if err != nil {
return "", fmt.Errorf("can't read a file %q: %w", fileName, err)
}

fileValS := string(fileVal)
f, err := parser.ParseFile(token.NewFileSet(), fileName, fileValS, 0)
if err != nil {
return "", fmt.Errorf("can't parse a file %q: %w", fileName, err)
}
found := false
var functionBody string
ast.Inspect(f, func(node ast.Node) bool {
if found {
return false
}
fDecl, ok := node.(*ast.FuncDecl)
if ok && fDecl.Name.Name == funcName && fDecl.Body != nil {
found = true
functionBody = fileValS[fDecl.Body.Pos() : fDecl.Body.End()-2]
return false
}

return true
})

if !found {
return "", fmt.Errorf("can't read a file %q: %w", fileName, err)
}
return resetIndents(functionBody), nil
},
"quote_file": func(fileName string) (string, error) {
fileVal, err := ioutil.ReadFile(fileName)
if err != nil {
return "", fmt.Errorf("can't read a file %q: %w", fileName, err)
}

return strings.TrimRight(string(fileVal), "\n"), nil
},
"indent": indent,
})

if tpl, err = tpl.Parse(string(tplVal)); err != nil {
return fmt.Errorf("can't parse a template: %w", err)
}

const resFileName = "README.md"
resFile, err := os.Create(resFileName)
if err != nil {
return fmt.Errorf("can't create a result file %q: %w", resFileName, err)
}

if err = tpl.Execute(resFile, nil); err != nil {
return fmt.Errorf("can't execute template: %w", err)
}

return nil
}

func resetIndents(s string) string {
minCountOfLeadingSpaces := -1
lines := strings.Split(strings.Trim(s, "\n"), "\n")
for _, line := range lines {
trimmed := strings.TrimLeftFunc(line, unicode.IsSpace)
if utf8.RuneCountInString(trimmed) == 0 {
continue
}
countOfLeadingSpaces := utf8.RuneCountInString(line) - utf8.RuneCountInString(trimmed)
if countOfLeadingSpaces < minCountOfLeadingSpaces || minCountOfLeadingSpaces == -1 {
minCountOfLeadingSpaces = countOfLeadingSpaces
}
}
if minCountOfLeadingSpaces == 0 {
return s
}
res := ""
for i, line := range lines {
if i != 0 {
res += "\n"
}
if utf8.RuneCountInString(line) == 0 {
continue
}
res += string([]rune(line)[minCountOfLeadingSpaces:])
}
return res
}

func indent(spaces int, v string) string {
pad := strings.Repeat(" ", spaces)
return pad + strings.Replace(v, "\n", "\n"+pad, -1)
}
11 changes: 11 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module github.com/vivid-money/article-golang-di

go 1.13

require (
github.com/google/wire v0.4.0
go.uber.org/dig v1.10.0
go.uber.org/fx v1.13.1
go.uber.org/multierr v1.6.0
golang.org/x/sync v0.0.0-20190423024810-112230192c58
)
65 changes: 65 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
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/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/subcommands v1.0.1 h1:/eqq+otEXm5vhfBrbREPCSVQbvofip6kIz+mX5TUH7k=
github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
github.com/google/wire v0.4.0 h1:kXcsA/rIGzJImVqPdhfnr6q0xsS9gU0515q1EPpJ9fE=
github.com/google/wire v0.4.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
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/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/dig v1.10.0 h1:yLmDDj9/zuDjv3gz8GQGviXMs9TfysIUMUilCpgzUJY=
go.uber.org/dig v1.10.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw=
go.uber.org/fx v1.13.1 h1:CFNTr1oin5OJ0VCZ8EycL3wzF29Jz2g0xe55RFsf2a4=
go.uber.org/fx v1.13.1/go.mod h1:bREWhavnedxpJeTq9pQT53BbvwhUv7TcpsOqcH4a+3w=
go.uber.org/goleak v0.10.0 h1:G3eWbSNIskeRqtsN/1uI5B+eP73y3JUuBsv9AZjehb4=
go.uber.org/goleak v0.10.0/go.mod h1:VCZuO8V8mFPlL0F5J5GK1rtHV3DrFcQ1R8ryq7FK0aI=
go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191030062658-86caa796c7ab/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191114200427-caa0b0f7d508 h1:0FYNp0PF9kFm/ZUrvcJiQ12IUJJG7iAc6Cu01wbKrbU=
golang.org/x/tools v0.0.0-20191114200427-caa0b0f7d508/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
41 changes: 41 additions & 0 deletions pkg/components/dbconn.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package components

import (
"context"
"sync"
)

// Fake db connection.
type DBConn struct {
logger Logger
once sync.Once
}

func NewDBConn(logger Logger) *DBConn {
logger.Print("New DBConn")
return &DBConn{
logger: logger,
}
}

func (h *DBConn) Connect(ctx context.Context) error {
h.logger.Print("Connecting DBConn")
defer h.logger.Print("Connected DBConn")
go func() { // эмулируем остановку соединения по отмене контекста
<-ctx.Done()
_ = h.Stop(context.Background())
}()
return nil
}

func (h *DBConn) Stop(_ context.Context) error {
h.once.Do(func() {
h.logger.Print("Stop DBConn")
defer h.logger.Print("Stopped DBConn")
})
return nil
}

func (h *DBConn) Query(_ string) (string, error) {
return "Fake result", nil
}
18 changes: 18 additions & 0 deletions pkg/components/helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package components

import (
"context"
"os"
"os/signal"
"syscall"
)

// Простенький хелпер, чтобы не писать один и тот же код несколько раз.
func AwaitSignal(ctx context.Context) {
sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
select {
case <-ctx.Done():
case <-sig:
}
}
61 changes: 61 additions & 0 deletions pkg/components/http_server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package components

import (
"context"
"fmt"
"net/http"
)

type HTTPServer struct {
httpSrv *http.Server
conn *DBConn
logger Logger
}

func NewHTTPServer(logger Logger, conn *DBConn) *HTTPServer {
logger.Print("New HTTPServer")
mux := http.NewServeMux()

s := &HTTPServer{
conn: conn,
logger: logger,
}
mux.HandleFunc("/get", func(writer http.ResponseWriter, _ *http.Request) {
res, err := conn.Query("SELECT * FROM something")
if err != nil {
writer.WriteHeader(http.StatusInternalServerError)
return
}
_, _ = writer.Write([]byte(res))
})
s.httpSrv = &http.Server{
Addr: ":3000",
Handler: mux,
}

return s
}

func (s *HTTPServer) Serve(ctx context.Context) error {
s.logger.Print("Serving HTTPServer")
defer s.logger.Print("Finished serving HTTPServer")
go func() { // вызываем остановку по отмене контекста, так как net/http не умеет работать с контекстами
<-ctx.Done()
_ = s.Stop(context.Background())
}()
if err := s.httpSrv.ListenAndServe(); err != nil {
return fmt.Errorf("http listen: %w", err)
}

return nil
}

func (s *HTTPServer) Stop(ctx context.Context) error {
s.logger.Print("Stop HTTPServer")
defer s.logger.Print("Stopped HTTPServer")
if err := s.httpSrv.Shutdown(ctx); err != nil {
return fmt.Errorf("http shutdown: %w", err)
}

return nil
}
10 changes: 10 additions & 0 deletions pkg/components/logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package components

type Logger interface {
Print(v ...interface{})
Printf(format string, v ...interface{})
Fatal(v ...interface{})
Fatalf(format string, v ...interface{})
Panic(v ...interface{})
Panicf(format string, v ...interface{})
}
Loading

0 comments on commit d84b83b

Please sign in to comment.