Compare commits
9 Commits
a5435699cb
...
11255805b1
Author | SHA1 | Date |
---|---|---|
Maxim Lebedev | 11255805b1 | |
Maxim Lebedev | dd29a48db3 | |
Maxim Lebedev | 1ee4956afd | |
Maxim Lebedev | 28a1498f76 | |
Maxim Lebedev | d0a00f0331 | |
Maxim Lebedev | 71ee3e4da4 | |
Maxim Lebedev | 9678e99140 | |
Maxim Lebedev | 26ea6b7939 | |
Maxim Lebedev | 884e390b79 |
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/make -f
|
||||
SHELL = /bin/sh
|
||||
|
||||
#### Start of system configuration section. ####
|
||||
|
||||
srcdir = .
|
||||
|
||||
GO ?= go
|
||||
GOFLAGS ?= -buildvcs=true
|
||||
EXECUTABLE ?= hub
|
||||
|
||||
#### End of system configuration section. ####
|
||||
|
||||
.PHONY: all
|
||||
all: main.go
|
||||
$(GO) build -v $(GOFLAGS) -o $(EXECUTABLE)
|
||||
|
||||
.PHONY: clean
|
||||
clean: ## Delete all files in the current directory that are normally created by building the program
|
||||
$(GO) clean
|
||||
|
||||
.PHONY: check
|
||||
check: ## Perform self-tests
|
||||
$(GO) test -v -cover -failfast -short -shuffle=on $(GOFLAGS) $(srcdir)/...
|
||||
|
||||
.PHONY: help
|
||||
help: ## Display this help screen
|
||||
@grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
|
@ -0,0 +1,49 @@
|
|||
---
|
||||
kind: "pipeline"
|
||||
type: "docker"
|
||||
name: "default"
|
||||
|
||||
environment:
|
||||
CGO_ENABLED: 0
|
||||
|
||||
steps:
|
||||
- name: "test"
|
||||
image: "golang:alpine"
|
||||
volumes:
|
||||
- name: "modules"
|
||||
path: "/go/pkg/mod"
|
||||
commands:
|
||||
- "make check"
|
||||
|
||||
- name: "build"
|
||||
image: "golang:alpine"
|
||||
volumes:
|
||||
- name: "modules"
|
||||
path: "/go/pkg/mod"
|
||||
commands:
|
||||
- "make"
|
||||
depends_on:
|
||||
- "test"
|
||||
|
||||
- name: "delivery"
|
||||
image: "drillster/drone-rsync"
|
||||
settings:
|
||||
hosts:
|
||||
from_secret: "SSH_HOST_IP"
|
||||
key:
|
||||
from_secret: "SSH_PRIVATE_KEY"
|
||||
source: "./hub"
|
||||
target: "/etc/hub/"
|
||||
prescript:
|
||||
- "systemctl stop websub"
|
||||
script:
|
||||
- "systemctl start websub"
|
||||
depends_on:
|
||||
- build
|
||||
when:
|
||||
branch:
|
||||
- master
|
||||
|
||||
volumes:
|
||||
- name: modules
|
||||
temp: {}
|
|
@ -39,29 +39,30 @@ func init() {
|
|||
}
|
||||
|
||||
var messageKeyToIndex = map[string]int{
|
||||
"%d subscribers": 4,
|
||||
"%s logo": 0,
|
||||
"Dead simple WebSub hub": 1,
|
||||
"How to publish and consume?": 2,
|
||||
"What the spec?": 3,
|
||||
"%d subscribers": 5,
|
||||
"%s logo": 1,
|
||||
"Dead simple WebSub hub": 2,
|
||||
"How to publish and consume?": 3,
|
||||
"What the spec?": 4,
|
||||
"version": 0,
|
||||
}
|
||||
|
||||
var enIndex = []uint32{ // 6 elements
|
||||
0x00000000, 0x0000000b, 0x00000022, 0x0000003e,
|
||||
0x0000004d, 0x0000005f,
|
||||
} // Size: 48 bytes
|
||||
var enIndex = []uint32{ // 7 elements
|
||||
0x00000000, 0x00000008, 0x00000013, 0x0000002a,
|
||||
0x00000046, 0x00000055, 0x00000067,
|
||||
} // Size: 52 bytes
|
||||
|
||||
const enData string = "" + // Size: 95 bytes
|
||||
"\x02%[1]s logo\x02Dead simple WebSub hub\x02How to publish and consume?" +
|
||||
"\x02What the spec?\x02%[1]d subscribers"
|
||||
const enData string = "" + // Size: 103 bytes
|
||||
"\x02version\x02%[1]s logo\x02Dead simple WebSub hub\x02How to publish an" +
|
||||
"d consume?\x02What the spec?\x02%[1]d subscribers"
|
||||
|
||||
var ruIndex = []uint32{ // 6 elements
|
||||
0x00000000, 0x00000015, 0x00000038, 0x0000006d,
|
||||
0x00000083, 0x000000a0,
|
||||
} // Size: 48 bytes
|
||||
var ruIndex = []uint32{ // 7 elements
|
||||
0x00000000, 0x0000000d, 0x00000022, 0x00000045,
|
||||
0x0000007a, 0x00000090, 0x000000ad,
|
||||
} // Size: 52 bytes
|
||||
|
||||
const ruData string = "" + // Size: 160 bytes
|
||||
"\x02логотип %[1]s\x02Простейший хаб WebSub\x02Как публиковать и принимат" +
|
||||
"ь?\x02В чём спека?\x02%[1]d подписчиков"
|
||||
const ruData string = "" + // Size: 173 bytes
|
||||
"\x02версия\x02логотип %[1]s\x02Простейший хаб WebSub\x02Как публиковать " +
|
||||
"и принимать?\x02В чём спека?\x02%[1]d подписчиков"
|
||||
|
||||
// Total table size 351 bytes (0KiB); checksum: D963980B
|
||||
// Total table size 380 bytes (0KiB); checksum: 7D8C2E8B
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
# WebSub [![Build Status](https://drone.toby3d.me/api/badges/toby3d/hub/status.svg)](https://drone.toby3d.me/toby3d/hub)
|
||||
> Personal WebSub hub
|
2
go.mod
2
go.mod
|
@ -4,7 +4,7 @@ go 1.20
|
|||
|
||||
require (
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.0
|
||||
github.com/caarlos0/env/v6 v6.10.1
|
||||
github.com/caarlos0/env/v7 v7.1.0
|
||||
github.com/go-logfmt/logfmt v0.6.0
|
||||
github.com/jmoiron/sqlx v1.3.5
|
||||
github.com/valyala/quicktemplate v1.7.0
|
||||
|
|
4
go.sum
4
go.sum
|
@ -2,8 +2,8 @@ github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20O
|
|||
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||
github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/caarlos0/env/v6 v6.10.1 h1:t1mPSxNpei6M5yAeu1qtRdPAK29Nbcf/n3G7x+b3/II=
|
||||
github.com/caarlos0/env/v6 v6.10.1/go.mod h1:hvp/ryKXKipEkcuYjs9mI4bBCg+UI0Yhgm5Zu0ddvwc=
|
||||
github.com/caarlos0/env/v7 v7.1.0 h1:9lzTF5amyQeWHZzuZeKlCb5FWSUxpG1js43mhbY8ozg=
|
||||
github.com/caarlos0/env/v7 v7.1.0/go.mod h1:LPPWniDUq4JaO6Q41vtlyikhMknqymCLBw0eX4dcH1E=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
[Unit]
|
||||
Description=WebSub Hub
|
||||
After=syslog.target
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
EnvironmentFile=/etc/hub/env
|
||||
RestartSec=2s
|
||||
Type=simple
|
||||
WorkingDirectory=/etc/hub/
|
||||
ExecStart=/etc/hub/hub
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -7,7 +7,7 @@ import (
|
|||
|
||||
type Config struct {
|
||||
BaseURL *url.URL `env:"BASE_URL" envDefault:"http://localhost:3000/"`
|
||||
Bind string `end:"BIND" envDefault:":3000"`
|
||||
Bind string `end:"BIND,required" envDefault:":3000"`
|
||||
Name string `env:"NAME" envDefault:"WebSub"`
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ func TestHandler_ServeHTTP_Subscribe(t *testing.T) {
|
|||
w := httptest.NewRecorder()
|
||||
delivery.NewHandler(delivery.NewHandlerParams{
|
||||
Hub: hub,
|
||||
Subscriptions: subscriptionucase.NewSubscriptionUseCase(subscriptions, topics),
|
||||
Subscriptions: subscriptionucase.NewSubscriptionUseCase(subscriptions, topics, srv.Client()),
|
||||
Topics: topicucase.NewTopicUseCase(topics, srv.Client()),
|
||||
Matcher: language.NewMatcher([]language.Tag{language.English}),
|
||||
Name: "WebSub",
|
||||
|
@ -94,7 +94,7 @@ func TestHandler_ServeHTTP_Unsubscribe(t *testing.T) {
|
|||
w := httptest.NewRecorder()
|
||||
delivery.NewHandler(delivery.NewHandlerParams{
|
||||
Hub: hub,
|
||||
Subscriptions: subscriptionucase.NewSubscriptionUseCase(subscriptions, topics),
|
||||
Subscriptions: subscriptionucase.NewSubscriptionUseCase(subscriptions, topics, srv.Client()),
|
||||
Topics: topicucase.NewTopicUseCase(topics, srv.Client()),
|
||||
Matcher: language.NewMatcher([]language.Tag{language.English}),
|
||||
Name: "WebSub",
|
||||
|
|
|
@ -2,8 +2,13 @@ package usecase_test
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"source.toby3d.me/toby3d/hub/internal/common"
|
||||
"source.toby3d.me/toby3d/hub/internal/domain"
|
||||
subscriptionmemoryrepo "source.toby3d.me/toby3d/hub/internal/subscription/repository/memory"
|
||||
"source.toby3d.me/toby3d/hub/internal/subscription/usecase"
|
||||
|
@ -13,11 +18,24 @@ import (
|
|||
func TestSubscriptionUseCase_Subscribe(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
subscription := domain.TestSubscription(t, "https://example.com/")
|
||||
topic := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.Header().Set(common.HeaderContentType, common.MIMETextPlainCharsetUTF8)
|
||||
fmt.Fprint(w, "hello, world")
|
||||
}))
|
||||
t.Cleanup(topic.Close)
|
||||
|
||||
callback := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.Header().Set(common.HeaderContentType, common.MIMETextPlainCharsetUTF8)
|
||||
fmt.Fprint(w, "hello, world")
|
||||
}))
|
||||
t.Cleanup(callback.Close)
|
||||
|
||||
subscription := domain.TestSubscription(t, callback.URL)
|
||||
subscription.Topic, _ = url.Parse(topic.URL + "/")
|
||||
topics := topicmemoryrepo.NewMemoryTopicRepository()
|
||||
subscriptions := subscriptionmemoryrepo.NewMemorySubscriptionRepository()
|
||||
|
||||
ucase := usecase.NewSubscriptionUseCase(subscriptions, topics)
|
||||
ucase := usecase.NewSubscriptionUseCase(subscriptions, topics, callback.Client())
|
||||
|
||||
ok, err := ucase.Subscribe(context.Background(), *subscription)
|
||||
if err != nil {
|
||||
|
@ -49,6 +67,12 @@ func TestSubscriptionUseCase_Subscribe(t *testing.T) {
|
|||
func TestSubscriptionUseCase_Unsubscribe(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
srv := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.Header().Set(common.HeaderContentType, common.MIMETextPlainCharsetUTF8)
|
||||
fmt.Fprint(w, "hello, world")
|
||||
}))
|
||||
t.Cleanup(srv.Close)
|
||||
|
||||
subscription := domain.TestSubscription(t, "https://example.com/")
|
||||
topics := topicmemoryrepo.NewMemoryTopicRepository()
|
||||
subscriptions := subscriptionmemoryrepo.NewMemorySubscriptionRepository()
|
||||
|
@ -57,7 +81,7 @@ func TestSubscriptionUseCase_Unsubscribe(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ok, err := usecase.NewSubscriptionUseCase(subscriptions, topics).
|
||||
ok, err := usecase.NewSubscriptionUseCase(subscriptions, topics, srv.Client()).
|
||||
Unsubscribe(context.Background(), *subscription)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
{
|
||||
"language": "en",
|
||||
"messages": [
|
||||
{
|
||||
"id": "version",
|
||||
"message": "version",
|
||||
"translation": "version",
|
||||
"translatorComment": "Copied from source.",
|
||||
"fuzzy": true
|
||||
},
|
||||
{
|
||||
"id": "{Name} logo",
|
||||
"message": "{Name} logo",
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
{
|
||||
"language": "ru",
|
||||
"messages": [
|
||||
{
|
||||
"id": "version",
|
||||
"message": "version",
|
||||
"translation": "версия"
|
||||
},
|
||||
{
|
||||
"id": "{Name} logo",
|
||||
"message": "{Name} logo",
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
{
|
||||
"language": "ru",
|
||||
"messages": [
|
||||
{
|
||||
"id": "version",
|
||||
"message": "version",
|
||||
"translation": "версия"
|
||||
},
|
||||
{
|
||||
"id": "{Name} logo",
|
||||
"message": "{Name} logo",
|
||||
|
|
9
main.go
9
main.go
|
@ -14,7 +14,7 @@ import (
|
|||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/caarlos0/env/v6"
|
||||
"github.com/caarlos0/env/v7"
|
||||
"golang.org/x/text/feature/plural"
|
||||
"golang.org/x/text/language"
|
||||
"golang.org/x/text/message"
|
||||
|
@ -56,7 +56,11 @@ func main() {
|
|||
ctx := context.Background()
|
||||
|
||||
config := new(domain.Config)
|
||||
if err := env.Parse(config, env.Options{Prefix: "HUB_"}); err != nil {
|
||||
if err := env.Parse(config, env.Options{
|
||||
Prefix: "HUB_",
|
||||
TagName: "env",
|
||||
UseFieldNameByDefault: true,
|
||||
}); err != nil {
|
||||
logger.Fatalln(err)
|
||||
}
|
||||
|
||||
|
@ -100,6 +104,7 @@ func main() {
|
|||
|
||||
go hubService.ListenAndServe(ctx)
|
||||
|
||||
logger.Printf("started %s on %s: %s", config.Name, config.Bind, config.BaseURL.String())
|
||||
if err = server.ListenAndServe(); err != nil {
|
||||
logger.Fatalln(err)
|
||||
}
|
||||
|
|
141
vendor/github.com/caarlos0/env/v6/README.md → vendor/github.com/caarlos0/env/v7/README.md
generated
vendored
141
vendor/github.com/caarlos0/env/v6/README.md → vendor/github.com/caarlos0/env/v7/README.md
generated
vendored
|
@ -1,8 +1,8 @@
|
|||
# env
|
||||
|
||||
[![Build Status](https://img.shields.io/github/workflow/status/caarlos0/env/build?style=for-the-badge)](https://github.com/caarlos0/env/actions?workflow=build)
|
||||
[![Build Status](https://img.shields.io/github/actions/workflow/status/caarlos0/env/build.yml?branch=main&style=for-the-badge)](https://github.com/caarlos0/env/actions?workflow=build)
|
||||
[![Coverage Status](https://img.shields.io/codecov/c/gh/caarlos0/env.svg?logo=codecov&style=for-the-badge)](https://codecov.io/gh/caarlos0/env)
|
||||
[![](http://img.shields.io/badge/godoc-reference-5272B4.svg?style=for-the-badge)](https://pkg.go.dev/github.com/caarlos0/env/v6)
|
||||
[![](http://img.shields.io/badge/godoc-reference-5272B4.svg?style=for-the-badge)](https://pkg.go.dev/github.com/caarlos0/env/v7)
|
||||
|
||||
A simple and zero-dependencies library to parse environment variables into structs.
|
||||
|
||||
|
@ -11,7 +11,7 @@ A simple and zero-dependencies library to parse environment variables into struc
|
|||
Get the module with:
|
||||
|
||||
```sh
|
||||
go get github.com/caarlos0/env/v6
|
||||
go get github.com/caarlos0/env/v7
|
||||
```
|
||||
|
||||
The usage looks like this:
|
||||
|
@ -23,7 +23,7 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/caarlos0/env/v6"
|
||||
"github.com/caarlos0/env/v7"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
|
@ -53,7 +53,14 @@ $ PRODUCTION=true HOSTS="host1:host2:host3" DURATION=1s go run main.go
|
|||
{Home:/your/home Port:3000 IsProduction:true Hosts:[host1 host2 host3] Duration:1s}
|
||||
```
|
||||
|
||||
⚠️⚠️⚠️ **Attention:** _unexported fields_ will be **ignored**.
|
||||
## Caveats
|
||||
|
||||
> **Warning**
|
||||
>
|
||||
> **This is important!**
|
||||
|
||||
- _Unexported fields_ are **ignored**
|
||||
|
||||
|
||||
## Supported types and defaults
|
||||
|
||||
|
@ -80,11 +87,15 @@ Complete list:
|
|||
- `encoding.TextUnmarshaler`
|
||||
- `url.URL`
|
||||
|
||||
Pointers, slices and slices of pointers of those types are also supported.
|
||||
Pointers, slices and slices of pointers, and maps of those types are also
|
||||
supported.
|
||||
|
||||
You can also use/define a [custom parser func](#custom-parser-funcs) for any
|
||||
other type you want.
|
||||
|
||||
You can also use custom keys and values in your maps, as long as you provide a
|
||||
parser function for them.
|
||||
|
||||
If you set the `envDefault` tag for something, this value will be used in the
|
||||
case of absence of it in the environment.
|
||||
|
||||
|
@ -107,7 +118,7 @@ also accepts a `map[reflect.Type]env.ParserFunc`.
|
|||
If you add a custom parser for, say `Foo`, it will also be used to parse
|
||||
`*Foo` and `[]Foo` types.
|
||||
|
||||
Check the examples in the [go doc](http://pkg.go.dev/github.com/caarlos0/env/v6)
|
||||
Check the examples in the [go doc](http://pkg.go.dev/github.com/caarlos0/env/v7)
|
||||
for more info.
|
||||
|
||||
### A note about `TextUnmarshaler` and `time.Time`
|
||||
|
@ -148,7 +159,7 @@ type config struct {
|
|||
|
||||
## Not Empty fields
|
||||
|
||||
While `required` demands the environment variable to be check, it doesn't check its value.
|
||||
While `required` demands the environment variable to be set, it doesn't check its value.
|
||||
If you want to make sure the environment is set and not empty, you need to use the `notEmpty` tag option instead (`env:"SOME_ENV,notEmpty"`).
|
||||
|
||||
Example:
|
||||
|
@ -185,7 +196,7 @@ package main
|
|||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"github.com/caarlos0/env/v6"
|
||||
"github.com/caarlos0/env/v7"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
|
@ -217,6 +228,46 @@ $ SECRET=/tmp/secret \
|
|||
|
||||
## Options
|
||||
|
||||
### Use field names as environment variables by default
|
||||
|
||||
If you don't want to set the `env` tag on every field, you can use the
|
||||
`UseFieldNameByDefault` option.
|
||||
|
||||
It will use the field name as environment variable name.
|
||||
|
||||
Here's an example:
|
||||
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/caarlos0/env/v7"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Username string // will use $USERNAME
|
||||
Password string // will use $PASSWORD
|
||||
UserFullName string // will use $USER_FULL_NAME
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfg := &Config{}
|
||||
opts := &env.Options{UseFieldNameByDefault: true}
|
||||
|
||||
// Load env vars.
|
||||
if err := env.Parse(cfg, opts); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Print the loaded data.
|
||||
fmt.Printf("%+v\n", cfg)
|
||||
}
|
||||
```
|
||||
|
||||
### Environment
|
||||
|
||||
By setting the `Options.Environment` map you can tell `Parse` to add those `keys` and `values`
|
||||
|
@ -232,7 +283,7 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/caarlos0/env/v6"
|
||||
"github.com/caarlos0/env/v7"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
|
@ -251,7 +302,7 @@ func main() {
|
|||
}
|
||||
|
||||
// Print the loaded data.
|
||||
fmt.Printf("%+v\n", cfg.envData)
|
||||
fmt.Printf("%+v\n", cfg)
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -268,7 +319,7 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/caarlos0/env/v6"
|
||||
"github.com/caarlos0/env/v7"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
|
@ -285,7 +336,7 @@ func main() {
|
|||
}
|
||||
|
||||
// Print the loaded data.
|
||||
fmt.Printf("%+v\n", cfg.envData)
|
||||
fmt.Printf("%+v\n", cfg)
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -302,7 +353,7 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/caarlos0/env/v6"
|
||||
"github.com/caarlos0/env/v7"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
|
@ -318,7 +369,7 @@ type ComplexConfig struct {
|
|||
|
||||
func main() {
|
||||
cfg := ComplexConfig{}
|
||||
if err := Parse(&cfg, Options{
|
||||
if err := Parse(&cfg, Options{
|
||||
Prefix: "T_",
|
||||
Environment: map[string]string{
|
||||
"T_FOO_HOME": "/foo",
|
||||
|
@ -336,7 +387,7 @@ func main() {
|
|||
}
|
||||
|
||||
// Print the loaded data.
|
||||
fmt.Printf("%+v\n", cfg.envData)
|
||||
fmt.Printf("%+v\n", cfg)
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -352,7 +403,7 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/caarlos0/env/v6"
|
||||
"github.com/caarlos0/env/v7"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
|
@ -374,7 +425,7 @@ func main() {
|
|||
}
|
||||
|
||||
// Print the loaded data.
|
||||
fmt.Printf("%+v\n", cfg.envData)
|
||||
fmt.Printf("%+v\n", cfg)
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -391,7 +442,7 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/caarlos0/env/v6"
|
||||
"github.com/caarlos0/env/v7"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
|
@ -409,7 +460,7 @@ func main() {
|
|||
}
|
||||
|
||||
// Print the loaded data.
|
||||
fmt.Printf("%+v\n", cfg.envData)
|
||||
fmt.Printf("%+v\n", cfg)
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -425,7 +476,7 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/caarlos0/env/v6"
|
||||
"github.com/caarlos0/env/v7"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
|
@ -447,6 +498,54 @@ func main() {
|
|||
}
|
||||
```
|
||||
|
||||
## Error handling
|
||||
|
||||
You can handle the errors the library throws like so:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/caarlos0/env/v7"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Username string `env:"USERNAME" envDefault:"admin"`
|
||||
Password string `env:"PASSWORD"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
var cfg Config
|
||||
err := env.Parse(&cfg)
|
||||
if e, ok := err.(*env.AggregateError); ok {
|
||||
for _, er := range e.Errors {
|
||||
switch v := er.(type) {
|
||||
case env.ParseError:
|
||||
// handle it
|
||||
case env.NotStructPtrError:
|
||||
// handle it
|
||||
case env.NoParserError:
|
||||
// handle it
|
||||
case env.NoSupportedTagOptionError:
|
||||
// handle it
|
||||
default:
|
||||
fmt.Printf("Unknown error type %v", v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("%+v", cfg) // {Username:admin Password:123456}
|
||||
}
|
||||
```
|
||||
|
||||
> **Info**
|
||||
>
|
||||
> If you want to check if an specific error is in the chain, you can also use
|
||||
> `errors.Is()`.
|
||||
|
||||
## Stargazers over time
|
||||
|
||||
[![Stargazers over time](https://starchart.cc/caarlos0/env.svg)](https://starchart.cc/caarlos0/env)
|
152
vendor/github.com/caarlos0/env/v6/env.go → vendor/github.com/caarlos0/env/v7/env.go
generated
vendored
152
vendor/github.com/caarlos0/env/v6/env.go → vendor/github.com/caarlos0/env/v7/env.go
generated
vendored
|
@ -2,7 +2,6 @@ package env
|
|||
|
||||
import (
|
||||
"encoding"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
|
@ -10,14 +9,11 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// nolint: gochecknoglobals
|
||||
var (
|
||||
// ErrNotAStructPtr is returned if you pass something that is not a pointer to a
|
||||
// Struct to Parse.
|
||||
ErrNotAStructPtr = errors.New("env: expected a pointer to a Struct")
|
||||
|
||||
defaultBuiltInParsers = map[reflect.Kind]ParserFunc{
|
||||
reflect.Bool: func(v string) (interface{}, error) {
|
||||
return strconv.ParseBool(v)
|
||||
|
@ -79,14 +75,14 @@ func defaultTypeParsers() map[reflect.Type]ParserFunc {
|
|||
reflect.TypeOf(url.URL{}): func(v string) (interface{}, error) {
|
||||
u, err := url.Parse(v)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse URL: %v", err)
|
||||
return nil, newParseValueError("unable to parse URL", err)
|
||||
}
|
||||
return *u, nil
|
||||
},
|
||||
reflect.TypeOf(time.Nanosecond): func(v string) (interface{}, error) {
|
||||
s, err := time.ParseDuration(v)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse duration: %v", err)
|
||||
return nil, newParseValueError("unable to parse duration", err)
|
||||
}
|
||||
return s, err
|
||||
},
|
||||
|
@ -107,15 +103,20 @@ type Options struct {
|
|||
// TagName specifies another tagname to use rather than the default env.
|
||||
TagName string
|
||||
|
||||
// RequiredIfNoDef automatically sets all env as required if they do not declare 'envDefault'
|
||||
// RequiredIfNoDef automatically sets all env as required if they do not
|
||||
// declare 'envDefault'.
|
||||
RequiredIfNoDef bool
|
||||
|
||||
// OnSet allows to run a function when a value is set
|
||||
// OnSet allows to run a function when a value is set.
|
||||
OnSet OnSetFn
|
||||
|
||||
// Prefix define a prefix for each key
|
||||
// Prefix define a prefix for each key.
|
||||
Prefix string
|
||||
|
||||
// UseFieldNameByDefault defines whether or not env should use the field
|
||||
// name by default if the `env` key is missing.
|
||||
UseFieldNameByDefault bool
|
||||
|
||||
// Sets to true if we have already configured once.
|
||||
configured bool
|
||||
}
|
||||
|
@ -150,6 +151,7 @@ func configure(opts []Options) []Options {
|
|||
if item.Prefix != "" {
|
||||
opt.Prefix = item.Prefix
|
||||
}
|
||||
opt.UseFieldNameByDefault = item.UseFieldNameByDefault
|
||||
opt.RequiredIfNoDef = item.RequiredIfNoDef
|
||||
}
|
||||
|
||||
|
@ -183,11 +185,11 @@ func ParseWithFuncs(v interface{}, funcMap map[reflect.Type]ParserFunc, opts ...
|
|||
|
||||
ptrRef := reflect.ValueOf(v)
|
||||
if ptrRef.Kind() != reflect.Ptr {
|
||||
return ErrNotAStructPtr
|
||||
return newAggregateError(NotStructPtrError{})
|
||||
}
|
||||
ref := ptrRef.Elem()
|
||||
if ref.Kind() != reflect.Struct {
|
||||
return ErrNotAStructPtr
|
||||
return newAggregateError(NotStructPtrError{})
|
||||
}
|
||||
parsers := defaultTypeParsers()
|
||||
for k, v := range funcMap {
|
||||
|
@ -200,22 +202,22 @@ func ParseWithFuncs(v interface{}, funcMap map[reflect.Type]ParserFunc, opts ...
|
|||
func doParse(ref reflect.Value, funcMap map[reflect.Type]ParserFunc, opts []Options) error {
|
||||
refType := ref.Type()
|
||||
|
||||
var agrErr aggregateError
|
||||
var agrErr AggregateError
|
||||
|
||||
for i := 0; i < refType.NumField(); i++ {
|
||||
refField := ref.Field(i)
|
||||
refTypeField := refType.Field(i)
|
||||
|
||||
if err := doParseField(refField, refTypeField, funcMap, opts); err != nil {
|
||||
if val, ok := err.(aggregateError); ok {
|
||||
agrErr.errors = append(agrErr.errors, val.errors...)
|
||||
if val, ok := err.(AggregateError); ok {
|
||||
agrErr.Errors = append(agrErr.Errors, val.Errors...)
|
||||
} else {
|
||||
agrErr.errors = append(agrErr.errors, err)
|
||||
agrErr.Errors = append(agrErr.Errors, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(agrErr.errors) == 0 {
|
||||
if len(agrErr.Errors) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -226,7 +228,7 @@ func doParseField(refField reflect.Value, refTypeField reflect.StructField, func
|
|||
if !refField.CanSet() {
|
||||
return nil
|
||||
}
|
||||
if reflect.Ptr == refField.Kind() && refField.Elem().Kind() == reflect.Struct {
|
||||
if reflect.Ptr == refField.Kind() && !refField.IsNil() {
|
||||
return ParseWithFuncs(refField.Interface(), funcMap, optsWithPrefix(refTypeField, opts)...)
|
||||
}
|
||||
if reflect.Struct == refField.Kind() && refField.CanAddr() && refField.Type().Name() == "" {
|
||||
|
@ -248,6 +250,19 @@ func doParseField(refField reflect.Value, refTypeField reflect.StructField, func
|
|||
return nil
|
||||
}
|
||||
|
||||
const underscore rune = '_'
|
||||
|
||||
func toEnvName(input string) string {
|
||||
var output []rune
|
||||
for i, c := range input {
|
||||
if i > 0 && output[i-1] != underscore && c != underscore && unicode.ToUpper(c) == c {
|
||||
output = append(output, underscore)
|
||||
}
|
||||
output = append(output, unicode.ToUpper(c))
|
||||
}
|
||||
return string(output)
|
||||
}
|
||||
|
||||
func get(field reflect.StructField, opts []Options) (val string, err error) {
|
||||
var exists bool
|
||||
var isDefault bool
|
||||
|
@ -258,6 +273,9 @@ func get(field reflect.StructField, opts []Options) (val string, err error) {
|
|||
required := opts[0].RequiredIfNoDef
|
||||
prefix := opts[0].Prefix
|
||||
ownKey, tags := parseKeyForOption(field.Tag.Get(getTagName(opts)))
|
||||
if ownKey == "" && opts[0].UseFieldNameByDefault {
|
||||
ownKey = toEnvName(field.Name)
|
||||
}
|
||||
key := prefix + ownKey
|
||||
for _, tag := range tags {
|
||||
switch tag {
|
||||
|
@ -272,7 +290,7 @@ func get(field reflect.StructField, opts []Options) (val string, err error) {
|
|||
case "notEmpty":
|
||||
notEmpty = true
|
||||
default:
|
||||
return "", fmt.Errorf("tag option %q not supported", tag)
|
||||
return "", newNoSupportedTagOptionError(tag)
|
||||
}
|
||||
}
|
||||
expand := strings.EqualFold(field.Tag.Get("envExpand"), "true")
|
||||
|
@ -288,18 +306,18 @@ func get(field reflect.StructField, opts []Options) (val string, err error) {
|
|||
}
|
||||
|
||||
if required && !exists && len(ownKey) > 0 {
|
||||
return "", fmt.Errorf(`required environment variable %q is not set`, key)
|
||||
return "", newEnvVarIsNotSet(key)
|
||||
}
|
||||
|
||||
if notEmpty && val == "" {
|
||||
return "", fmt.Errorf("environment variable %q should not be empty", key)
|
||||
return "", newEmptyEnvVarError(key)
|
||||
}
|
||||
|
||||
if loadFile && val != "" {
|
||||
filename := val
|
||||
val, err = getFromFile(filename)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf(`could not load content of file "%s" from variable %s: %v`, filename, key, err)
|
||||
return "", newLoadFileContentError(filename, key, err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -325,6 +343,8 @@ func getOr(key, defaultValue string, defExists bool, envs map[string]string) (st
|
|||
switch {
|
||||
case (!exists || key == "") && defExists:
|
||||
return defaultValue, true, true
|
||||
case exists && value == "" && defExists:
|
||||
return defaultValue, true, true
|
||||
case !exists:
|
||||
return "", false, false
|
||||
}
|
||||
|
@ -369,8 +389,11 @@ func set(field reflect.Value, sf reflect.StructField, value string, funcMap map[
|
|||
return nil
|
||||
}
|
||||
|
||||
if field.Kind() == reflect.Slice {
|
||||
switch field.Kind() {
|
||||
case reflect.Slice:
|
||||
return handleSlice(field, value, sf, funcMap)
|
||||
case reflect.Map:
|
||||
return handleMap(field, value, sf, funcMap)
|
||||
}
|
||||
|
||||
return newNoParserError(sf)
|
||||
|
@ -417,6 +440,54 @@ func handleSlice(field reflect.Value, value string, sf reflect.StructField, func
|
|||
return nil
|
||||
}
|
||||
|
||||
func handleMap(field reflect.Value, value string, sf reflect.StructField, funcMap map[reflect.Type]ParserFunc) error {
|
||||
keyType := sf.Type.Key()
|
||||
keyParserFunc, ok := funcMap[keyType]
|
||||
if !ok {
|
||||
keyParserFunc, ok = defaultBuiltInParsers[keyType.Kind()]
|
||||
if !ok {
|
||||
return newNoParserError(sf)
|
||||
}
|
||||
}
|
||||
|
||||
elemType := sf.Type.Elem()
|
||||
elemParserFunc, ok := funcMap[elemType]
|
||||
if !ok {
|
||||
elemParserFunc, ok = defaultBuiltInParsers[elemType.Kind()]
|
||||
if !ok {
|
||||
return newNoParserError(sf)
|
||||
}
|
||||
}
|
||||
|
||||
separator := sf.Tag.Get("envSeparator")
|
||||
if separator == "" {
|
||||
separator = ","
|
||||
}
|
||||
|
||||
result := reflect.MakeMap(sf.Type)
|
||||
for _, part := range strings.Split(value, separator) {
|
||||
pairs := strings.Split(part, ":")
|
||||
if len(pairs) != 2 {
|
||||
return newParseError(sf, fmt.Errorf(`%q should be in "key:value" format`, part))
|
||||
}
|
||||
|
||||
key, err := keyParserFunc(pairs[0])
|
||||
if err != nil {
|
||||
return newParseError(sf, err)
|
||||
}
|
||||
|
||||
elem, err := elemParserFunc(pairs[1])
|
||||
if err != nil {
|
||||
return newParseError(sf, err)
|
||||
}
|
||||
|
||||
result.SetMapIndex(reflect.ValueOf(key).Convert(keyType), reflect.ValueOf(elem).Convert(elemType))
|
||||
}
|
||||
|
||||
field.Set(result)
|
||||
return nil
|
||||
}
|
||||
|
||||
func asTextUnmarshaler(field reflect.Value) encoding.TextUnmarshaler {
|
||||
if reflect.Ptr == field.Kind() {
|
||||
if field.IsNil() {
|
||||
|
@ -459,26 +530,6 @@ func parseTextUnmarshalers(field reflect.Value, data []string, sf reflect.Struct
|
|||
return nil
|
||||
}
|
||||
|
||||
func newParseError(sf reflect.StructField, err error) error {
|
||||
return parseError{
|
||||
sf: sf,
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
type parseError struct {
|
||||
sf reflect.StructField
|
||||
err error
|
||||
}
|
||||
|
||||
func (e parseError) Error() string {
|
||||
return fmt.Sprintf(`parse error on field "%s" of type "%s": %v`, e.sf.Name, e.sf.Type, e.err)
|
||||
}
|
||||
|
||||
func newNoParserError(sf reflect.StructField) error {
|
||||
return fmt.Errorf(`no parser found for field "%s" of type "%s"`, sf.Name, sf.Type)
|
||||
}
|
||||
|
||||
func optsWithPrefix(field reflect.StructField, opts []Options) []Options {
|
||||
subOpts := make([]Options, len(opts))
|
||||
copy(subOpts, opts)
|
||||
|
@ -487,18 +538,3 @@ func optsWithPrefix(field reflect.StructField, opts []Options) []Options {
|
|||
}
|
||||
return subOpts
|
||||
}
|
||||
|
||||
type aggregateError struct {
|
||||
errors []error
|
||||
}
|
||||
|
||||
func (e aggregateError) Error() string {
|
||||
var sb strings.Builder
|
||||
sb.WriteString("env:")
|
||||
|
||||
for _, err := range e.errors {
|
||||
sb.WriteString(fmt.Sprintf(" %v;", err.Error()))
|
||||
}
|
||||
|
||||
return strings.TrimRight(sb.String(), ";")
|
||||
}
|
|
@ -0,0 +1,164 @@
|
|||
package env
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// An aggregated error wrapper to combine gathered errors. This allows either to display all errors or convert them individually
|
||||
// List of the available errors
|
||||
// ParseError
|
||||
// NotStructPtrError
|
||||
// NoParserError
|
||||
// NoSupportedTagOptionError
|
||||
// EnvVarIsNotSetError
|
||||
// EmptyEnvVarError
|
||||
// LoadFileContentError
|
||||
// ParseValueError
|
||||
type AggregateError struct {
|
||||
Errors []error
|
||||
}
|
||||
|
||||
func newAggregateError(initErr error) error {
|
||||
return AggregateError{
|
||||
[]error{
|
||||
initErr,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (e AggregateError) Error() string {
|
||||
var sb strings.Builder
|
||||
|
||||
sb.WriteString("env:")
|
||||
|
||||
for _, err := range e.Errors {
|
||||
sb.WriteString(fmt.Sprintf(" %v;", err.Error()))
|
||||
}
|
||||
|
||||
return strings.TrimRight(sb.String(), ";")
|
||||
}
|
||||
|
||||
// Is conforms with errors.Is.
|
||||
func (e AggregateError) Is(err error) bool {
|
||||
for _, ie := range e.Errors {
|
||||
if reflect.TypeOf(ie) == reflect.TypeOf(err) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// The error occurs when it's impossible to convert the value for given type.
|
||||
type ParseError struct {
|
||||
Name string
|
||||
Type reflect.Type
|
||||
Err error
|
||||
}
|
||||
|
||||
func newParseError(sf reflect.StructField, err error) error {
|
||||
return ParseError{sf.Name, sf.Type, err}
|
||||
}
|
||||
|
||||
func (e ParseError) Error() string {
|
||||
return fmt.Sprintf(`parse error on field "%s" of type "%s": %v`, e.Name, e.Type, e.Err)
|
||||
}
|
||||
|
||||
// The error occurs when pass something that is not a pointer to a Struct to Parse
|
||||
type NotStructPtrError struct{}
|
||||
|
||||
func (e NotStructPtrError) Error() string {
|
||||
return "expected a pointer to a Struct"
|
||||
}
|
||||
|
||||
// This error occurs when there is no parser provided for given type
|
||||
// Supported types and defaults: https://github.com/caarlos0/env#supported-types-and-defaults
|
||||
// How to create a custom parser: https://github.com/caarlos0/env#custom-parser-funcs
|
||||
type NoParserError struct {
|
||||
Name string
|
||||
Type reflect.Type
|
||||
}
|
||||
|
||||
func newNoParserError(sf reflect.StructField) error {
|
||||
return NoParserError{sf.Name, sf.Type}
|
||||
}
|
||||
|
||||
func (e NoParserError) Error() string {
|
||||
return fmt.Sprintf(`no parser found for field "%s" of type "%s"`, e.Name, e.Type)
|
||||
}
|
||||
|
||||
// This error occurs when the given tag is not supported
|
||||
// In-built supported tags: "", "file", "required", "unset", "notEmpty", "envDefault", "envExpand", "envSeparator"
|
||||
// How to create a custom tag: https://github.com/caarlos0/env#changing-default-tag-name
|
||||
type NoSupportedTagOptionError struct {
|
||||
Tag string
|
||||
}
|
||||
|
||||
func newNoSupportedTagOptionError(tag string) error {
|
||||
return NoSupportedTagOptionError{tag}
|
||||
}
|
||||
|
||||
func (e NoSupportedTagOptionError) Error() string {
|
||||
return fmt.Sprintf("tag option %q not supported", e.Tag)
|
||||
}
|
||||
|
||||
// This error occurs when the required variable is not set
|
||||
// Read about required fields: https://github.com/caarlos0/env#required-fields
|
||||
type EnvVarIsNotSetError struct {
|
||||
Key string
|
||||
}
|
||||
|
||||
func newEnvVarIsNotSet(key string) error {
|
||||
return EnvVarIsNotSetError{key}
|
||||
}
|
||||
|
||||
func (e EnvVarIsNotSetError) Error() string {
|
||||
return fmt.Sprintf(`required environment variable %q is not set`, e.Key)
|
||||
}
|
||||
|
||||
// This error occurs when the variable which must be not empty is existing but has an empty value
|
||||
// Read about not empty fields: https://github.com/caarlos0/env#not-empty-fields
|
||||
type EmptyEnvVarError struct {
|
||||
Key string
|
||||
}
|
||||
|
||||
func newEmptyEnvVarError(key string) error {
|
||||
return EmptyEnvVarError{key}
|
||||
}
|
||||
|
||||
func (e EmptyEnvVarError) Error() string {
|
||||
return fmt.Sprintf("environment variable %q should not be empty", e.Key)
|
||||
}
|
||||
|
||||
// This error occurs when it's impossible to load the value from the file
|
||||
// Read about From file feature: https://github.com/caarlos0/env#from-file
|
||||
type LoadFileContentError struct {
|
||||
Filename string
|
||||
Key string
|
||||
Err error
|
||||
}
|
||||
|
||||
func newLoadFileContentError(filename, key string, err error) error {
|
||||
return LoadFileContentError{filename, key, err}
|
||||
}
|
||||
|
||||
func (e LoadFileContentError) Error() string {
|
||||
return fmt.Sprintf(`could not load content of file "%s" from variable %s: %v`, e.Filename, e.Key, e.Err)
|
||||
}
|
||||
|
||||
// This error occurs when it's impossible to convert value using given parser
|
||||
// Supported types and defaults: https://github.com/caarlos0/env#supported-types-and-defaults
|
||||
// How to create a custom parser: https://github.com/caarlos0/env#custom-parser-funcs
|
||||
type ParseValueError struct {
|
||||
Msg string
|
||||
Err error
|
||||
}
|
||||
|
||||
func newParseValueError(message string, err error) error {
|
||||
return ParseValueError{message, err}
|
||||
}
|
||||
|
||||
func (e ParseValueError) Error() string {
|
||||
return fmt.Sprintf("%s: %v", e.Msg, e.Err)
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
# github.com/DATA-DOG/go-sqlmock v1.5.0
|
||||
## explicit
|
||||
github.com/DATA-DOG/go-sqlmock
|
||||
# github.com/caarlos0/env/v6 v6.10.1
|
||||
# github.com/caarlos0/env/v7 v7.1.0
|
||||
## explicit; go 1.17
|
||||
github.com/caarlos0/env/v6
|
||||
github.com/caarlos0/env/v7
|
||||
# github.com/dustin/go-humanize v1.0.1
|
||||
## explicit; go 1.16
|
||||
github.com/dustin/go-humanize
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
{% import (
|
||||
"runtime/debug"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
"golang.org/x/text/message"
|
||||
) %}
|
||||
|
@ -81,6 +83,53 @@ func NewBaseOf(lang language.Tag, name string) *BaseOf {
|
|||
|
||||
<body class="page__body cover">
|
||||
{%= p.body() %}
|
||||
|
||||
{% code
|
||||
var path, vcsRevision string
|
||||
|
||||
if bi, ok := debug.ReadBuildInfo(); ok {
|
||||
path = bi.Path
|
||||
|
||||
for i := range bi.Settings {
|
||||
if bi.Settings[i].Key != "vcs.revision" {
|
||||
continue
|
||||
}
|
||||
|
||||
vcsRevision = bi.Settings[i].Value
|
||||
}
|
||||
}
|
||||
%}
|
||||
|
||||
<footer class="[ body__footer ][ center ][ text-align_center ]">
|
||||
<p>
|
||||
Made with
|
||||
<span role="img"
|
||||
aria-label="love">
|
||||
❤️
|
||||
</span>
|
||||
to
|
||||
<a rel="external"
|
||||
href="https://{%s path %}">
|
||||
open source
|
||||
</a>
|
||||
by
|
||||
<a rel="author"
|
||||
hreflang="en"
|
||||
href="https://toby3d.me/">
|
||||
toby3d
|
||||
</a>
|
||||
</p>
|
||||
|
||||
{% if vcsRevision != "" %}
|
||||
<small>
|
||||
{%= p.t("version") %}
|
||||
<a href="https://{%s path %}/commit/{%s vcsRevision %}"
|
||||
target="_blank">
|
||||
{%s vcsRevision[:7] -%}
|
||||
</a>
|
||||
</small>
|
||||
{% endif %}
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
{% endfunc %}
|
||||
|
|
|
@ -6,59 +6,61 @@ package template
|
|||
|
||||
//line web/template/baseof.qtpl:1
|
||||
import (
|
||||
"runtime/debug"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
"golang.org/x/text/message"
|
||||
)
|
||||
|
||||
//line web/template/baseof.qtpl:6
|
||||
//line web/template/baseof.qtpl:8
|
||||
import (
|
||||
qtio422016 "io"
|
||||
|
||||
qt422016 "github.com/valyala/quicktemplate"
|
||||
)
|
||||
|
||||
//line web/template/baseof.qtpl:6
|
||||
//line web/template/baseof.qtpl:8
|
||||
var (
|
||||
_ = qtio422016.Copy
|
||||
_ = qt422016.AcquireByteBuffer
|
||||
)
|
||||
|
||||
//line web/template/baseof.qtpl:6
|
||||
//line web/template/baseof.qtpl:8
|
||||
type Page interface {
|
||||
//line web/template/baseof.qtpl:6
|
||||
//line web/template/baseof.qtpl:8
|
||||
body() string
|
||||
//line web/template/baseof.qtpl:6
|
||||
//line web/template/baseof.qtpl:8
|
||||
streambody(qw422016 *qt422016.Writer)
|
||||
//line web/template/baseof.qtpl:6
|
||||
//line web/template/baseof.qtpl:8
|
||||
writebody(qq422016 qtio422016.Writer)
|
||||
//line web/template/baseof.qtpl:6
|
||||
//line web/template/baseof.qtpl:8
|
||||
head() string
|
||||
//line web/template/baseof.qtpl:6
|
||||
//line web/template/baseof.qtpl:8
|
||||
streamhead(qw422016 *qt422016.Writer)
|
||||
//line web/template/baseof.qtpl:6
|
||||
//line web/template/baseof.qtpl:8
|
||||
writehead(qq422016 qtio422016.Writer)
|
||||
//line web/template/baseof.qtpl:6
|
||||
//line web/template/baseof.qtpl:8
|
||||
lang() string
|
||||
//line web/template/baseof.qtpl:6
|
||||
//line web/template/baseof.qtpl:8
|
||||
streamlang(qw422016 *qt422016.Writer)
|
||||
//line web/template/baseof.qtpl:6
|
||||
//line web/template/baseof.qtpl:8
|
||||
writelang(qq422016 qtio422016.Writer)
|
||||
//line web/template/baseof.qtpl:6
|
||||
//line web/template/baseof.qtpl:8
|
||||
t(format message.Reference, args ...any) string
|
||||
//line web/template/baseof.qtpl:6
|
||||
//line web/template/baseof.qtpl:8
|
||||
streamt(qw422016 *qt422016.Writer, format message.Reference, args ...any)
|
||||
//line web/template/baseof.qtpl:6
|
||||
//line web/template/baseof.qtpl:8
|
||||
writet(qq422016 qtio422016.Writer, format message.Reference, args ...any)
|
||||
//line web/template/baseof.qtpl:6
|
||||
//line web/template/baseof.qtpl:8
|
||||
title() string
|
||||
//line web/template/baseof.qtpl:6
|
||||
//line web/template/baseof.qtpl:8
|
||||
streamtitle(qw422016 *qt422016.Writer)
|
||||
//line web/template/baseof.qtpl:6
|
||||
//line web/template/baseof.qtpl:8
|
||||
writetitle(qq422016 qtio422016.Writer)
|
||||
//line web/template/baseof.qtpl:6
|
||||
//line web/template/baseof.qtpl:8
|
||||
}
|
||||
|
||||
//line web/template/baseof.qtpl:15
|
||||
//line web/template/baseof.qtpl:17
|
||||
type BaseOf struct {
|
||||
language language.Tag
|
||||
printer *message.Printer
|
||||
|
@ -73,228 +75,273 @@ func NewBaseOf(lang language.Tag, name string) *BaseOf {
|
|||
}
|
||||
}
|
||||
|
||||
//line web/template/baseof.qtpl:31
|
||||
//line web/template/baseof.qtpl:33
|
||||
func (p *BaseOf) streamlang(qw422016 *qt422016.Writer) {
|
||||
//line web/template/baseof.qtpl:31
|
||||
//line web/template/baseof.qtpl:33
|
||||
qw422016.N().S(` `)
|
||||
//line web/template/baseof.qtpl:32
|
||||
//line web/template/baseof.qtpl:34
|
||||
qw422016.E().S(p.language.String())
|
||||
//line web/template/baseof.qtpl:32
|
||||
//line web/template/baseof.qtpl:34
|
||||
qw422016.N().S(` `)
|
||||
//line web/template/baseof.qtpl:33
|
||||
//line web/template/baseof.qtpl:35
|
||||
}
|
||||
|
||||
//line web/template/baseof.qtpl:33
|
||||
//line web/template/baseof.qtpl:35
|
||||
func (p *BaseOf) writelang(qq422016 qtio422016.Writer) {
|
||||
//line web/template/baseof.qtpl:33
|
||||
//line web/template/baseof.qtpl:35
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line web/template/baseof.qtpl:33
|
||||
//line web/template/baseof.qtpl:35
|
||||
p.streamlang(qw422016)
|
||||
//line web/template/baseof.qtpl:33
|
||||
//line web/template/baseof.qtpl:35
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line web/template/baseof.qtpl:33
|
||||
//line web/template/baseof.qtpl:35
|
||||
}
|
||||
|
||||
//line web/template/baseof.qtpl:33
|
||||
//line web/template/baseof.qtpl:35
|
||||
func (p *BaseOf) lang() string {
|
||||
//line web/template/baseof.qtpl:33
|
||||
//line web/template/baseof.qtpl:35
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line web/template/baseof.qtpl:33
|
||||
//line web/template/baseof.qtpl:35
|
||||
p.writelang(qb422016)
|
||||
//line web/template/baseof.qtpl:33
|
||||
//line web/template/baseof.qtpl:35
|
||||
qs422016 := string(qb422016.B)
|
||||
//line web/template/baseof.qtpl:33
|
||||
//line web/template/baseof.qtpl:35
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line web/template/baseof.qtpl:33
|
||||
//line web/template/baseof.qtpl:35
|
||||
return qs422016
|
||||
//line web/template/baseof.qtpl:33
|
||||
//line web/template/baseof.qtpl:35
|
||||
}
|
||||
|
||||
//line web/template/baseof.qtpl:35
|
||||
//line web/template/baseof.qtpl:37
|
||||
func (p *BaseOf) streamtitle(qw422016 *qt422016.Writer) {
|
||||
//line web/template/baseof.qtpl:35
|
||||
//line web/template/baseof.qtpl:37
|
||||
qw422016.N().S(` `)
|
||||
//line web/template/baseof.qtpl:36
|
||||
//line web/template/baseof.qtpl:38
|
||||
qw422016.E().S(p.name)
|
||||
//line web/template/baseof.qtpl:36
|
||||
//line web/template/baseof.qtpl:38
|
||||
qw422016.N().S(` `)
|
||||
//line web/template/baseof.qtpl:37
|
||||
//line web/template/baseof.qtpl:39
|
||||
}
|
||||
|
||||
//line web/template/baseof.qtpl:37
|
||||
//line web/template/baseof.qtpl:39
|
||||
func (p *BaseOf) writetitle(qq422016 qtio422016.Writer) {
|
||||
//line web/template/baseof.qtpl:37
|
||||
//line web/template/baseof.qtpl:39
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line web/template/baseof.qtpl:37
|
||||
//line web/template/baseof.qtpl:39
|
||||
p.streamtitle(qw422016)
|
||||
//line web/template/baseof.qtpl:37
|
||||
//line web/template/baseof.qtpl:39
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line web/template/baseof.qtpl:37
|
||||
//line web/template/baseof.qtpl:39
|
||||
}
|
||||
|
||||
//line web/template/baseof.qtpl:37
|
||||
//line web/template/baseof.qtpl:39
|
||||
func (p *BaseOf) title() string {
|
||||
//line web/template/baseof.qtpl:37
|
||||
//line web/template/baseof.qtpl:39
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line web/template/baseof.qtpl:37
|
||||
//line web/template/baseof.qtpl:39
|
||||
p.writetitle(qb422016)
|
||||
//line web/template/baseof.qtpl:37
|
||||
//line web/template/baseof.qtpl:39
|
||||
qs422016 := string(qb422016.B)
|
||||
//line web/template/baseof.qtpl:37
|
||||
//line web/template/baseof.qtpl:39
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line web/template/baseof.qtpl:37
|
||||
//line web/template/baseof.qtpl:39
|
||||
return qs422016
|
||||
//line web/template/baseof.qtpl:37
|
||||
//line web/template/baseof.qtpl:39
|
||||
}
|
||||
|
||||
//line web/template/baseof.qtpl:39
|
||||
//line web/template/baseof.qtpl:41
|
||||
func (p *BaseOf) streamhead(qw422016 *qt422016.Writer) {
|
||||
//line web/template/baseof.qtpl:39
|
||||
//line web/template/baseof.qtpl:41
|
||||
qw422016.N().S(` `)
|
||||
//line web/template/baseof.qtpl:40
|
||||
qw422016.N().S(` <link rel="icon" href="/static/favicon.ico" sizes="any"> <link rel="icon" href="/static/icon.svg" type="image/svg+xml"> <link rel="apple-touch-icon" href="/static/apple-touch-icon.png"> <link rel="manifest" href="/static/manifest.webmanifest"> `)
|
||||
//line web/template/baseof.qtpl:54
|
||||
//line web/template/baseof.qtpl:42
|
||||
qw422016.N().S(` <link rel="manifest" href="/static/manifest.webmanifest"> <link rel="icon" href="/static/favicon.ico" sizes="any"> <link rel="icon" href="/static/icon.svg" type="image/svg+xml"> <link rel="apple-touch-icon" href="/static/apple-touch-icon.png"> `)
|
||||
//line web/template/baseof.qtpl:56
|
||||
}
|
||||
|
||||
//line web/template/baseof.qtpl:54
|
||||
//line web/template/baseof.qtpl:56
|
||||
func (p *BaseOf) writehead(qq422016 qtio422016.Writer) {
|
||||
//line web/template/baseof.qtpl:54
|
||||
//line web/template/baseof.qtpl:56
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line web/template/baseof.qtpl:54
|
||||
//line web/template/baseof.qtpl:56
|
||||
p.streamhead(qw422016)
|
||||
//line web/template/baseof.qtpl:54
|
||||
//line web/template/baseof.qtpl:56
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line web/template/baseof.qtpl:54
|
||||
//line web/template/baseof.qtpl:56
|
||||
}
|
||||
|
||||
//line web/template/baseof.qtpl:54
|
||||
//line web/template/baseof.qtpl:56
|
||||
func (p *BaseOf) head() string {
|
||||
//line web/template/baseof.qtpl:54
|
||||
//line web/template/baseof.qtpl:56
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line web/template/baseof.qtpl:54
|
||||
//line web/template/baseof.qtpl:56
|
||||
p.writehead(qb422016)
|
||||
//line web/template/baseof.qtpl:54
|
||||
//line web/template/baseof.qtpl:56
|
||||
qs422016 := string(qb422016.B)
|
||||
//line web/template/baseof.qtpl:54
|
||||
//line web/template/baseof.qtpl:56
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line web/template/baseof.qtpl:54
|
||||
//line web/template/baseof.qtpl:56
|
||||
return qs422016
|
||||
//line web/template/baseof.qtpl:54
|
||||
//line web/template/baseof.qtpl:56
|
||||
}
|
||||
|
||||
//line web/template/baseof.qtpl:56
|
||||
//line web/template/baseof.qtpl:58
|
||||
func (p *BaseOf) streambody(qw422016 *qt422016.Writer) {
|
||||
//line web/template/baseof.qtpl:56
|
||||
//line web/template/baseof.qtpl:58
|
||||
}
|
||||
|
||||
//line web/template/baseof.qtpl:56
|
||||
//line web/template/baseof.qtpl:58
|
||||
func (p *BaseOf) writebody(qq422016 qtio422016.Writer) {
|
||||
//line web/template/baseof.qtpl:56
|
||||
//line web/template/baseof.qtpl:58
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line web/template/baseof.qtpl:56
|
||||
//line web/template/baseof.qtpl:58
|
||||
p.streambody(qw422016)
|
||||
//line web/template/baseof.qtpl:56
|
||||
//line web/template/baseof.qtpl:58
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line web/template/baseof.qtpl:56
|
||||
//line web/template/baseof.qtpl:58
|
||||
}
|
||||
|
||||
//line web/template/baseof.qtpl:56
|
||||
//line web/template/baseof.qtpl:58
|
||||
func (p *BaseOf) body() string {
|
||||
//line web/template/baseof.qtpl:56
|
||||
//line web/template/baseof.qtpl:58
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line web/template/baseof.qtpl:56
|
||||
//line web/template/baseof.qtpl:58
|
||||
p.writebody(qb422016)
|
||||
//line web/template/baseof.qtpl:56
|
||||
//line web/template/baseof.qtpl:58
|
||||
qs422016 := string(qb422016.B)
|
||||
//line web/template/baseof.qtpl:56
|
||||
//line web/template/baseof.qtpl:58
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line web/template/baseof.qtpl:56
|
||||
//line web/template/baseof.qtpl:58
|
||||
return qs422016
|
||||
//line web/template/baseof.qtpl:56
|
||||
//line web/template/baseof.qtpl:58
|
||||
}
|
||||
|
||||
//line web/template/baseof.qtpl:58
|
||||
//line web/template/baseof.qtpl:60
|
||||
func (p *BaseOf) streamt(qw422016 *qt422016.Writer, format message.Reference, args ...any) {
|
||||
//line web/template/baseof.qtpl:58
|
||||
//line web/template/baseof.qtpl:60
|
||||
qw422016.N().S(` `)
|
||||
//line web/template/baseof.qtpl:59
|
||||
//line web/template/baseof.qtpl:61
|
||||
qw422016.E().S(p.printer.Sprintf(format, args...))
|
||||
//line web/template/baseof.qtpl:59
|
||||
//line web/template/baseof.qtpl:61
|
||||
qw422016.N().S(` `)
|
||||
//line web/template/baseof.qtpl:60
|
||||
//line web/template/baseof.qtpl:62
|
||||
}
|
||||
|
||||
//line web/template/baseof.qtpl:60
|
||||
//line web/template/baseof.qtpl:62
|
||||
func (p *BaseOf) writet(qq422016 qtio422016.Writer, format message.Reference, args ...any) {
|
||||
//line web/template/baseof.qtpl:60
|
||||
//line web/template/baseof.qtpl:62
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line web/template/baseof.qtpl:60
|
||||
//line web/template/baseof.qtpl:62
|
||||
p.streamt(qw422016, format, args...)
|
||||
//line web/template/baseof.qtpl:60
|
||||
//line web/template/baseof.qtpl:62
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line web/template/baseof.qtpl:60
|
||||
//line web/template/baseof.qtpl:62
|
||||
}
|
||||
|
||||
//line web/template/baseof.qtpl:60
|
||||
//line web/template/baseof.qtpl:62
|
||||
func (p *BaseOf) t(format message.Reference, args ...any) string {
|
||||
//line web/template/baseof.qtpl:60
|
||||
//line web/template/baseof.qtpl:62
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line web/template/baseof.qtpl:60
|
||||
//line web/template/baseof.qtpl:62
|
||||
p.writet(qb422016, format, args...)
|
||||
//line web/template/baseof.qtpl:60
|
||||
//line web/template/baseof.qtpl:62
|
||||
qs422016 := string(qb422016.B)
|
||||
//line web/template/baseof.qtpl:60
|
||||
//line web/template/baseof.qtpl:62
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line web/template/baseof.qtpl:60
|
||||
//line web/template/baseof.qtpl:62
|
||||
return qs422016
|
||||
//line web/template/baseof.qtpl:60
|
||||
//line web/template/baseof.qtpl:62
|
||||
}
|
||||
|
||||
//line web/template/baseof.qtpl:62
|
||||
//line web/template/baseof.qtpl:64
|
||||
func StreamTemplate(qw422016 *qt422016.Writer, p Page) {
|
||||
//line web/template/baseof.qtpl:62
|
||||
//line web/template/baseof.qtpl:64
|
||||
qw422016.N().S(` <!DOCTYPE html> <html class="page" lang="`)
|
||||
//line web/template/baseof.qtpl:65
|
||||
//line web/template/baseof.qtpl:67
|
||||
p.streamlang(qw422016)
|
||||
//line web/template/baseof.qtpl:65
|
||||
//line web/template/baseof.qtpl:67
|
||||
qw422016.N().S(`" dir="ltr"> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>`)
|
||||
//line web/template/baseof.qtpl:72
|
||||
//line web/template/baseof.qtpl:74
|
||||
p.streamtitle(qw422016)
|
||||
//line web/template/baseof.qtpl:72
|
||||
//line web/template/baseof.qtpl:74
|
||||
qw422016.N().S(`</title> <link rel="preload stylesheet" as="style" href="/static/style.css" type="text/css"> `)
|
||||
//line web/template/baseof.qtpl:79
|
||||
//line web/template/baseof.qtpl:81
|
||||
p.streamhead(qw422016)
|
||||
//line web/template/baseof.qtpl:79
|
||||
//line web/template/baseof.qtpl:81
|
||||
qw422016.N().S(` </head> <body class="page__body cover"> `)
|
||||
//line web/template/baseof.qtpl:83
|
||||
//line web/template/baseof.qtpl:85
|
||||
p.streambody(qw422016)
|
||||
//line web/template/baseof.qtpl:83
|
||||
qw422016.N().S(` </body> </html> `)
|
||||
//line web/template/baseof.qtpl:86
|
||||
//line web/template/baseof.qtpl:85
|
||||
qw422016.N().S(` `)
|
||||
//line web/template/baseof.qtpl:88
|
||||
var path, vcsRevision string
|
||||
|
||||
if bi, ok := debug.ReadBuildInfo(); ok {
|
||||
path = bi.Path
|
||||
|
||||
for i := range bi.Settings {
|
||||
if bi.Settings[i].Key != "vcs.revision" {
|
||||
continue
|
||||
}
|
||||
|
||||
vcsRevision = bi.Settings[i].Value
|
||||
}
|
||||
}
|
||||
|
||||
//line web/template/baseof.qtpl:101
|
||||
qw422016.N().S(` <footer class="[ body__footer ][ center ][ text-align_center ]"> <p> Made with <span role="img" aria-label="love"> ❤️ </span> to <a rel="external" href="https://`)
|
||||
//line web/template/baseof.qtpl:112
|
||||
qw422016.E().S(path)
|
||||
//line web/template/baseof.qtpl:112
|
||||
qw422016.N().S(`"> open source </a> by <a rel="author" hreflang="en" href="https://toby3d.me/"> toby3d </a> </p> `)
|
||||
//line web/template/baseof.qtpl:123
|
||||
if vcsRevision != "" {
|
||||
//line web/template/baseof.qtpl:123
|
||||
qw422016.N().S(` <small> `)
|
||||
//line web/template/baseof.qtpl:125
|
||||
p.streamt(qw422016, "version")
|
||||
//line web/template/baseof.qtpl:125
|
||||
qw422016.N().S(` <a href="https://`)
|
||||
//line web/template/baseof.qtpl:126
|
||||
qw422016.E().S(path)
|
||||
//line web/template/baseof.qtpl:126
|
||||
qw422016.N().S(`/commit/`)
|
||||
//line web/template/baseof.qtpl:126
|
||||
qw422016.E().S(vcsRevision)
|
||||
//line web/template/baseof.qtpl:126
|
||||
qw422016.N().S(`" target="_blank"> `)
|
||||
//line web/template/baseof.qtpl:128
|
||||
qw422016.E().S(vcsRevision[:7])
|
||||
//line web/template/baseof.qtpl:128
|
||||
qw422016.N().S(`</a> </small> `)
|
||||
//line web/template/baseof.qtpl:131
|
||||
}
|
||||
//line web/template/baseof.qtpl:131
|
||||
qw422016.N().S(` </footer> </body> </html> `)
|
||||
//line web/template/baseof.qtpl:135
|
||||
}
|
||||
|
||||
//line web/template/baseof.qtpl:86
|
||||
//line web/template/baseof.qtpl:135
|
||||
func WriteTemplate(qq422016 qtio422016.Writer, p Page) {
|
||||
//line web/template/baseof.qtpl:86
|
||||
//line web/template/baseof.qtpl:135
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line web/template/baseof.qtpl:86
|
||||
//line web/template/baseof.qtpl:135
|
||||
StreamTemplate(qw422016, p)
|
||||
//line web/template/baseof.qtpl:86
|
||||
//line web/template/baseof.qtpl:135
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line web/template/baseof.qtpl:86
|
||||
//line web/template/baseof.qtpl:135
|
||||
}
|
||||
|
||||
//line web/template/baseof.qtpl:86
|
||||
//line web/template/baseof.qtpl:135
|
||||
func Template(p Page) string {
|
||||
//line web/template/baseof.qtpl:86
|
||||
//line web/template/baseof.qtpl:135
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line web/template/baseof.qtpl:86
|
||||
//line web/template/baseof.qtpl:135
|
||||
WriteTemplate(qb422016, p)
|
||||
//line web/template/baseof.qtpl:86
|
||||
//line web/template/baseof.qtpl:135
|
||||
qs422016 := string(qb422016.B)
|
||||
//line web/template/baseof.qtpl:86
|
||||
//line web/template/baseof.qtpl:135
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line web/template/baseof.qtpl:86
|
||||
//line web/template/baseof.qtpl:135
|
||||
return qs422016
|
||||
//line web/template/baseof.qtpl:86
|
||||
//line web/template/baseof.qtpl:135
|
||||
}
|
||||
|
|
|
@ -51,27 +51,5 @@
|
|||
</li>
|
||||
</ul>
|
||||
</main>
|
||||
|
||||
<footer class="[ body__footer ][ center ][ text-align_center ]">
|
||||
<p>
|
||||
Made with
|
||||
<span role="img"
|
||||
aria-label="love">
|
||||
❤️
|
||||
</span>
|
||||
to
|
||||
<a rel="external"
|
||||
href="https://source.toby3d.me/toby3d/hub">
|
||||
open source
|
||||
</a>
|
||||
by
|
||||
<a rel="author"
|
||||
hreflang="en"
|
||||
href="https://toby3d.me/">
|
||||
toby3d
|
||||
</a>
|
||||
</p>
|
||||
<small>v1.0.0</small>
|
||||
</footer>
|
||||
{% endfunc %}
|
||||
{% endcollapsespace %}
|
||||
|
|
|
@ -45,32 +45,32 @@ func (p *Home) streambody(qw422016 *qt422016.Writer) {
|
|||
//line web/template/home.qtpl:49
|
||||
p.streamt(qw422016, "What the spec?")
|
||||
//line web/template/home.qtpl:49
|
||||
qw422016.N().S(` </a> </li> </ul> </main> <footer class="[ body__footer ][ center ][ text-align_center ]"> <p> Made with <span role="img" aria-label="love"> ❤️ </span> to <a rel="external" href="https://source.toby3d.me/toby3d/hub"> open source </a> by <a rel="author" hreflang="en" href="https://toby3d.me/"> toby3d </a> </p> <small>v1.0.0</small> </footer> `)
|
||||
//line web/template/home.qtpl:76
|
||||
qw422016.N().S(` </a> </li> </ul> </main> `)
|
||||
//line web/template/home.qtpl:54
|
||||
}
|
||||
|
||||
//line web/template/home.qtpl:76
|
||||
//line web/template/home.qtpl:54
|
||||
func (p *Home) writebody(qq422016 qtio422016.Writer) {
|
||||
//line web/template/home.qtpl:76
|
||||
//line web/template/home.qtpl:54
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line web/template/home.qtpl:76
|
||||
//line web/template/home.qtpl:54
|
||||
p.streambody(qw422016)
|
||||
//line web/template/home.qtpl:76
|
||||
//line web/template/home.qtpl:54
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line web/template/home.qtpl:76
|
||||
//line web/template/home.qtpl:54
|
||||
}
|
||||
|
||||
//line web/template/home.qtpl:76
|
||||
//line web/template/home.qtpl:54
|
||||
func (p *Home) body() string {
|
||||
//line web/template/home.qtpl:76
|
||||
//line web/template/home.qtpl:54
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line web/template/home.qtpl:76
|
||||
//line web/template/home.qtpl:54
|
||||
p.writebody(qb422016)
|
||||
//line web/template/home.qtpl:76
|
||||
//line web/template/home.qtpl:54
|
||||
qs422016 := string(qb422016.B)
|
||||
//line web/template/home.qtpl:76
|
||||
//line web/template/home.qtpl:54
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line web/template/home.qtpl:76
|
||||
//line web/template/home.qtpl:54
|
||||
return qs422016
|
||||
//line web/template/home.qtpl:76
|
||||
//line web/template/home.qtpl:54
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue