refactor asset with embed tool
This commit is contained in:
1
_build_vars
Normal file
1
_build_vars
Normal file
@@ -0,0 +1 @@
|
||||
export GO111MODULE=on
|
||||
@@ -1,7 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
GO111MODULES=on
|
||||
|
||||
source _build_vars
|
||||
go build \
|
||||
-tags "$(tr '\n' ' ' < _build_tags)" \
|
||||
cmd/scanner/main.go
|
||||
cmd/gonicscan/main.go
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
#!/bin/bash
|
||||
|
||||
GO111MODULES=on
|
||||
|
||||
./_do_compile_assets
|
||||
shopt -s globstar
|
||||
source _build_vars
|
||||
go run \
|
||||
cmd/gonicembed/main.go \
|
||||
-out-path server/assets_bytes.go \
|
||||
-tag-list embed \
|
||||
-package-name server \
|
||||
-assets-var-name AssetBytes \
|
||||
-asset-path-prefix server/assets/ \
|
||||
server/assets/**
|
||||
go build \
|
||||
-tags "$(tr '\n' ' ' < _build_tags) embed" \
|
||||
cmd/server/main.go
|
||||
cmd/gonic/main.go
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
shopt -s globstar
|
||||
|
||||
server_base_dir=server
|
||||
assets_name=assets
|
||||
|
||||
resources \
|
||||
-declare \
|
||||
-var $(sed -E 's/(^|_)([a-z])/\U\2/g' <<< $assets_name) \
|
||||
-package ${assets_name}_compiled \
|
||||
-output "$server_base_dir/${assets_name}_compiled/${assets_name}_compiled.go" \
|
||||
-trim "$server_base_dir/${assets_name}_src/" \
|
||||
"$server_base_dir/${assets_name}_src/"**
|
||||
@@ -1,8 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
GO111MODULES=on
|
||||
|
||||
source _build_vars
|
||||
go run \
|
||||
-tags "$(tr '\n' ' ' < _build_tags)" \
|
||||
cmd/scanner/main.go \
|
||||
cmd/gonicscan/main.go
|
||||
$@
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
GO111MODULES=on
|
||||
|
||||
source _build_vars
|
||||
go run \
|
||||
-tags "$(tr '\n' ' ' < _build_tags)" \
|
||||
cmd/server/main.go \
|
||||
cmd/gonic/main.go \
|
||||
$@
|
||||
|
||||
@@ -50,6 +50,7 @@ func main() {
|
||||
db,
|
||||
*musicPath,
|
||||
*listenAddr,
|
||||
"server/assets/",
|
||||
)
|
||||
err = s.SetupAdmin()
|
||||
if err != nil {
|
||||
147
cmd/gonicembed/main.go
Normal file
147
cmd/gonicembed/main.go
Normal file
@@ -0,0 +1,147 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/peterbourgon/ff"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
programName = "gonicembed"
|
||||
byteCols = 24
|
||||
|
||||
// begin file template
|
||||
fileHeader = `// file generated with embed tool
|
||||
// do not edit
|
||||
|
||||
// +build %s
|
||||
|
||||
package %s
|
||||
import "time"
|
||||
type EmbeddedAsset struct {
|
||||
ModTime time.Time
|
||||
Bytes []byte
|
||||
}
|
||||
var %s = map[string]*EmbeddedAsset{`
|
||||
fileFooter = `
|
||||
}`
|
||||
|
||||
// begin asset template
|
||||
assetHeader = `
|
||||
%q: &EmbeddedAsset{
|
||||
ModTime: time.Unix(%d, 0),
|
||||
Bytes: []byte{
|
||||
`
|
||||
assetFooter = `}},`
|
||||
)
|
||||
|
||||
type config struct {
|
||||
packageName string
|
||||
outPath string
|
||||
tagList string
|
||||
assetsVarName string
|
||||
assetPathPrefix string
|
||||
}
|
||||
|
||||
type file struct {
|
||||
data io.ReadSeeker
|
||||
path string
|
||||
modTime time.Time
|
||||
}
|
||||
|
||||
func processAsset(c *config, f *file, out io.Writer) error {
|
||||
out.Write([]byte(fmt.Sprintf(assetHeader,
|
||||
strings.TrimPrefix(f.path, c.assetPathPrefix),
|
||||
f.modTime.Unix(),
|
||||
)))
|
||||
defer out.Write([]byte(assetFooter))
|
||||
buffer := make([]byte, byteCols)
|
||||
for {
|
||||
read, err := f.data.Read(buffer)
|
||||
for i := 0; i < read; i++ {
|
||||
fmt.Fprintf(out, "0x%02x,", buffer[i])
|
||||
}
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
fmt.Fprintln(out)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func processAssets(c *config, files []string) error {
|
||||
outWriter, err := os.Create(c.outPath)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "creating out path")
|
||||
}
|
||||
outWriter.Write([]byte(fmt.Sprintf(fileHeader,
|
||||
c.tagList,
|
||||
c.packageName,
|
||||
c.assetsVarName,
|
||||
)))
|
||||
defer outWriter.Write([]byte(fileFooter))
|
||||
for _, path := range files {
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "stating asset")
|
||||
}
|
||||
if info.IsDir() {
|
||||
continue
|
||||
}
|
||||
data, err := os.Open(path)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "opening asset")
|
||||
}
|
||||
f := &file{
|
||||
data: data,
|
||||
path: path,
|
||||
modTime: info.ModTime(),
|
||||
}
|
||||
if err := processAsset(c, f, outWriter); err != nil {
|
||||
return errors.Wrap(err, "processing asset")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
set := flag.NewFlagSet(programName, flag.ExitOnError)
|
||||
outPath := set.String(
|
||||
"out-path", "",
|
||||
"generated file's path (required)")
|
||||
pkgName := set.String(
|
||||
"package-name", "assets",
|
||||
"generated file's package name")
|
||||
tagList := set.String(
|
||||
"tag-list", "",
|
||||
"generated file's build tag list")
|
||||
assetsVarName := set.String(
|
||||
"assets-var-name", "Assets",
|
||||
"generated file's assets var name")
|
||||
assetPathPrefix := set.String(
|
||||
"asset-path-prefix", "",
|
||||
"generated file's assets map key prefix to be stripped")
|
||||
if err := ff.Parse(set, os.Args[1:]); err != nil {
|
||||
log.Fatalf("error parsing args: %v\n", err)
|
||||
}
|
||||
if *outPath == "" {
|
||||
log.Fatalln("invalid arguments. see -h")
|
||||
}
|
||||
c := &config{
|
||||
packageName: *pkgName,
|
||||
outPath: *outPath,
|
||||
tagList: *tagList,
|
||||
assetsVarName: *assetsVarName,
|
||||
assetPathPrefix: *assetPathPrefix,
|
||||
}
|
||||
if err := processAssets(c, set.Args()); err != nil {
|
||||
log.Fatalf("error processing files: %v\n", err)
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
programName = "gonic"
|
||||
programName = "gonicscan"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -24,8 +24,7 @@ func main() {
|
||||
dbPath := set.String(
|
||||
"db-path", "gonic.db",
|
||||
"path to database (optional)")
|
||||
err := ff.Parse(set, os.Args[1:])
|
||||
if err != nil {
|
||||
if err := ff.Parse(set, os.Args[1:]); err != nil {
|
||||
log.Fatalf("error parsing args: %v\n", err)
|
||||
}
|
||||
if _, err := os.Stat(*musicPath); os.IsNotExist(err) {
|
||||
3
go.mod
3
go.mod
@@ -20,14 +20,13 @@ require (
|
||||
github.com/jinzhu/now v1.0.0 // indirect
|
||||
github.com/josephburnett/jd v0.0.0-20190523064723-9cd4cea55d7d
|
||||
github.com/karrick/godirwalk v1.8.0
|
||||
github.com/kr/pretty v0.1.0 // indirect
|
||||
github.com/lib/pq v1.0.0 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.10.0 // indirect
|
||||
github.com/nicksellen/audiotags v0.0.0-20160226222119-94015fa599bd
|
||||
github.com/omeid/go-resources v0.0.0-20190324090249-46f4269d8abd
|
||||
github.com/peterbourgon/ff v1.2.0
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be
|
||||
github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b
|
||||
github.com/wader/gormstore v0.0.0-20190302154359-acb787ba3755
|
||||
golang.org/x/crypto v0.0.0-20190422183909-d864b10871cd // indirect
|
||||
google.golang.org/appengine v1.5.0 // indirect
|
||||
|
||||
12
go.sum
12
go.sum
@@ -90,7 +90,12 @@ github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
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/pty v1.1.3/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/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o=
|
||||
@@ -99,8 +104,6 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nicksellen/audiotags v0.0.0-20160226222119-94015fa599bd h1:xKn/gU8lZupoZt/HE7a/R3aH93iUO6JwyRsYelQUsRI=
|
||||
github.com/nicksellen/audiotags v0.0.0-20160226222119-94015fa599bd/go.mod h1:B6icauz2l4tkYQxmDtCH4qmNWz/evSW5CsOqp6IE5IE=
|
||||
github.com/omeid/go-resources v0.0.0-20190324090249-46f4269d8abd h1:VxcHM9xpZ4BHxQPYWAavsxPciBZITxmnGNyIO7hsUfk=
|
||||
github.com/omeid/go-resources v0.0.0-20190324090249-46f4269d8abd/go.mod h1:SIESmZeFlCKsQZcd2NEiX8spNNmCWB1V/RbM/eBKDfo=
|
||||
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
||||
github.com/openzipkin/zipkin-go v0.1.3/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
||||
github.com/peterbourgon/ff v1.2.0 h1:wGn2NwdHk8MTlRQpnXnO91UKegxt5DvlwR/bTK/L2hc=
|
||||
@@ -122,10 +125,9 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R
|
||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be h1:ta7tUOvsPHVHGom5hKW5VXNc2xZIkfCKP8iaqOyYtUQ=
|
||||
github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be/go.mod h1:MIDFMn7db1kT65GmV94GzpX9Qdi7N/pQlwb+AN8wh+Q=
|
||||
github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b h1:4kg1wyftSKxLtnPAvcRWakIPpokB9w780/KwrNLnfPA=
|
||||
github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
||||
github.com/wader/gormstore v0.0.0-20190302154359-acb787ba3755 h1:pNaEDfvqe9W2h4D+xm5f+lnZdao3Rob6O0b8SovpGbE=
|
||||
@@ -155,6 +157,7 @@ golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73r
|
||||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
@@ -206,6 +209,7 @@ google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
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/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
||||
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 236 KiB After Width: | Height: | Size: 236 KiB |
@@ -4,12 +4,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>gonic</title>
|
||||
<link rel="stylesheet" href="/admin/static/stylesheets/reset.css">
|
||||
<link rel="stylesheet" href="https://cdn.materialdesignicons.com/3.6.95/css/materialdesignicons.min.css">
|
||||
<link rel="stylesheet" href="/admin/static/stylesheets/main.css">
|
||||
<link rel="shortcut icon" href="/admin/static/images/favicon.ico" type="image/x-icon">
|
||||
<link rel="icon" href="/admin/static/images/favicon.ico" type="image/x-icon">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
{{ template "head" }}
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
8
server/assets/partials/box.tmpl
Normal file
8
server/assets/partials/box.tmpl
Normal file
@@ -0,0 +1,8 @@
|
||||
{{ define "head" }}
|
||||
<link rel="stylesheet" href="/admin/static/stylesheets/reset.css">
|
||||
<link rel="stylesheet" href="https://cdn.materialdesignicons.com/3.6.95/css/materialdesignicons.min.css">
|
||||
<link rel="stylesheet" href="/admin/static/stylesheets/main.css">
|
||||
<link rel="shortcut icon" href="/admin/static/images/favicon.ico" type="image/x-icon">
|
||||
<link rel="icon" href="/admin/static/images/favicon.ico" type="image/x-icon">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
{{ end }}
|
||||
10652
server/assets_bytes.go
Normal file
10652
server/assets_bytes.go
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,9 +0,0 @@
|
||||
// +build !embed
|
||||
|
||||
package server
|
||||
|
||||
import "github.com/omeid/go-resources/live"
|
||||
|
||||
var (
|
||||
assets = live.Dir("./assets_src")
|
||||
)
|
||||
9
server/assets_getters.go
Normal file
9
server/assets_getters.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package server
|
||||
|
||||
import "errors"
|
||||
|
||||
var ErrAssetNotFound = errors.New("asset not found")
|
||||
|
||||
type Assets struct {
|
||||
BasePath string
|
||||
}
|
||||
39
server/assets_getters_dev.go
Normal file
39
server/assets_getters_dev.go
Normal file
@@ -0,0 +1,39 @@
|
||||
// +build !embed
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (a *Assets) Find(path string) (time.Time, io.ReadSeeker, error) {
|
||||
fullPath := filepath.Join(a.BasePath, path)
|
||||
info, err := os.Stat(fullPath)
|
||||
if err != nil {
|
||||
return time.Time{}, nil, errors.Wrap(err, "statting asset")
|
||||
}
|
||||
file, err := os.Open(fullPath)
|
||||
if err != nil {
|
||||
return time.Time{}, nil, errors.Wrapf(ErrAssetNotFound, "%v", err)
|
||||
}
|
||||
return info.ModTime(), file, nil
|
||||
}
|
||||
|
||||
func (a *Assets) FindBytes(path string) (time.Time, []byte, error) {
|
||||
fullPath := filepath.Join(a.BasePath, path)
|
||||
info, err := os.Stat(fullPath)
|
||||
if err != nil {
|
||||
return time.Time{}, nil, errors.Wrap(err, "statting asset")
|
||||
}
|
||||
file, err := ioutil.ReadFile(fullPath)
|
||||
if err != nil {
|
||||
return time.Time{}, nil, errors.Wrapf(ErrAssetNotFound, "%v", err)
|
||||
}
|
||||
return info.ModTime(), file, nil
|
||||
}
|
||||
26
server/assets_getters_prod.go
Normal file
26
server/assets_getters_prod.go
Normal file
@@ -0,0 +1,26 @@
|
||||
// +build embed
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (_ *Assets) Find(path string) (time.Time, io.ReadSeeker, error) {
|
||||
asset, ok := AssetBytes[path]
|
||||
if !ok {
|
||||
return time.Time{}, nil, ErrAssetNotFound
|
||||
}
|
||||
reader := bytes.NewReader(asset.Bytes)
|
||||
return asset.ModTime, reader, nil
|
||||
}
|
||||
|
||||
func (_ *Assets) FindBytes(path string) (time.Time, []byte, error) {
|
||||
asset, ok := AssetBytes[path]
|
||||
if !ok {
|
||||
return time.Time{}, nil, ErrAssetNotFound
|
||||
}
|
||||
return asset.ModTime, asset.Bytes, nil
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
// +build embed
|
||||
|
||||
package server
|
||||
|
||||
import "github.com/sentriz/gonic/server/assets_compiled"
|
||||
|
||||
var (
|
||||
assets = assets_compiled.Assets
|
||||
)
|
||||
@@ -1,10 +0,0 @@
|
||||
{{ define "box" }}
|
||||
<div class="padded box mono">
|
||||
<div class="box-title">
|
||||
<i class="mdi mdi-chart-arc"></i> {{ .Title }}
|
||||
</div>
|
||||
<div class="block-right">
|
||||
{{ .Content }}
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
@@ -25,11 +25,17 @@ func newChain(wares ...middleware) middleware {
|
||||
|
||||
type Server struct {
|
||||
mux *http.ServeMux
|
||||
assets *Assets
|
||||
*handler.Controller
|
||||
*http.Server
|
||||
}
|
||||
|
||||
func New(db *gorm.DB, musicPath string, listenAddr string) *Server {
|
||||
func New(
|
||||
db *gorm.DB,
|
||||
musicPath string,
|
||||
listenAddr string,
|
||||
assetPath string,
|
||||
) *Server {
|
||||
mux := http.NewServeMux()
|
||||
server := &http.Server{
|
||||
Addr: listenAddr,
|
||||
@@ -42,8 +48,12 @@ func New(db *gorm.DB, musicPath string, listenAddr string) *Server {
|
||||
DB: db,
|
||||
MusicPath: musicPath,
|
||||
}
|
||||
assets := &Assets{
|
||||
BasePath: assetPath,
|
||||
}
|
||||
return &Server{
|
||||
mux: mux,
|
||||
assets: assets,
|
||||
Server: server,
|
||||
Controller: controller,
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"html/template"
|
||||
"log"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"time"
|
||||
@@ -11,11 +11,74 @@ import (
|
||||
"github.com/dustin/go-humanize"
|
||||
"github.com/gorilla/securecookie"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/shurcooL/httpfs/html/vfstemplate"
|
||||
"github.com/shurcooL/httpfs/path/vfspath"
|
||||
"github.com/wader/gormstore"
|
||||
)
|
||||
|
||||
var (
|
||||
partialsPaths = []string{
|
||||
"partials/box.tmpl",
|
||||
}
|
||||
layoutPaths = []string{
|
||||
"layouts/base.tmpl",
|
||||
"layouts/user.tmpl",
|
||||
}
|
||||
pagePaths = []string{
|
||||
"pages/change_own_password.tmpl",
|
||||
"pages/change_password.tmpl",
|
||||
"pages/create_user.tmpl",
|
||||
"pages/delete_user.tmpl",
|
||||
"pages/home.tmpl",
|
||||
"pages/login.tmpl",
|
||||
"pages/update_lastfm_api_key.tmpl",
|
||||
}
|
||||
imagePaths = []string{
|
||||
"images/favicon.ico",
|
||||
"images/gonic.png",
|
||||
"images/gone.png",
|
||||
}
|
||||
stylesheetPaths = []string{
|
||||
"stylesheets/main.css",
|
||||
"stylesheets/reset.css",
|
||||
}
|
||||
)
|
||||
|
||||
type templateMap map[string]*template.Template
|
||||
|
||||
func parseFromPaths(assets *Assets, base *template.Template,
|
||||
paths []string, destination templateMap) error {
|
||||
for _, path := range paths {
|
||||
_, tmplBytes, err := assets.FindBytes(path)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "getting template %q from assets", path)
|
||||
}
|
||||
tmplStr := string(tmplBytes)
|
||||
if destination != nil {
|
||||
// we have a destination. meaning this template is a page.
|
||||
// instead of parsing as usual, we need to clone and add to the
|
||||
// template map
|
||||
clone := template.Must(base.Clone())
|
||||
tmplKey := filepath.Base(path)
|
||||
destination[tmplKey] = template.Must(clone.Parse(tmplStr))
|
||||
continue
|
||||
}
|
||||
_ = template.Must(base.Parse(tmplStr))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func staticHandler(assets *Assets, path string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
modTime, reader, err := assets.Find(path)
|
||||
if err != nil {
|
||||
log.Printf("error getting file %q from assets: %v\n", path, err)
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
_, name := filepath.Split(path)
|
||||
http.ServeContent(w, r, name, modTime, reader)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) SetupAdmin() error {
|
||||
sessionKey := []byte(s.GetSetting("session_key"))
|
||||
if len(sessionKey) == 0 {
|
||||
@@ -31,34 +94,18 @@ func (s *Server) SetupAdmin() error {
|
||||
Funcs(template.FuncMap{
|
||||
"humanDate": humanize.Time,
|
||||
})
|
||||
const (
|
||||
layoutDir = "/templates/layouts/*"
|
||||
partialDir = "/templates/partials/*"
|
||||
pageDir = "/templates/pages/*"
|
||||
)
|
||||
tmplLayouts, err := vfstemplate.ParseGlob(assets, tmplBase, layoutDir)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "parsing layouts")
|
||||
if err := parseFromPaths(
|
||||
s.assets, tmplBase, partialsPaths, nil); err != nil {
|
||||
return errors.Wrap(err, "parsing template partials")
|
||||
}
|
||||
tmplPartials, err := vfstemplate.ParseGlob(assets, tmplLayouts, partialDir)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "parsing partials")
|
||||
if err := parseFromPaths(
|
||||
s.assets, tmplBase, layoutPaths, nil); err != nil {
|
||||
return errors.Wrap(err, "parsing template layouts")
|
||||
}
|
||||
pages, err := vfspath.Glob(assets, pageDir)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "parsing pages")
|
||||
}
|
||||
s.Templates = make(map[string]*template.Template)
|
||||
for _, page := range pages {
|
||||
tmplStr, ok := assets.String(page)
|
||||
if !ok {
|
||||
return fmt.Errorf("getting template %q from assets: %v\n", page)
|
||||
}
|
||||
tmplBaseClone := template.Must(tmplPartials.Clone())
|
||||
tmplWithPage := template.Must(tmplBaseClone.Parse(tmplStr))
|
||||
tmplWithPartial := template.Must(tmplWithPage.Parse(tmplStr))
|
||||
shortName := filepath.Base(page)
|
||||
s.Templates[shortName] = tmplWithPartial
|
||||
s.Templates = make(templateMap)
|
||||
if err := parseFromPaths(
|
||||
s.assets, tmplBase, pagePaths, s.Templates); err != nil {
|
||||
return errors.Wrap(err, "parsing template pages for destination")
|
||||
}
|
||||
//
|
||||
withPublicWare := newChain(
|
||||
@@ -74,9 +121,10 @@ func (s *Server) SetupAdmin() error {
|
||||
s.WithAdminSession,
|
||||
)
|
||||
// begin static server
|
||||
s.mux.Handle("/admin/static/", http.StripPrefix("/admin",
|
||||
http.FileServer(assets),
|
||||
))
|
||||
for _, path := range append(imagePaths, stylesheetPaths...) {
|
||||
fullPath := filepath.Join("/admin/static", path)
|
||||
s.mux.HandleFunc(fullPath, staticHandler(s.assets, path))
|
||||
}
|
||||
// begin public routes (creates new session)
|
||||
s.mux.HandleFunc("/admin/login", withPublicWare(s.ServeLogin))
|
||||
s.mux.HandleFunc("/admin/login_do", withPublicWare(s.ServeLoginDo))
|
||||
|
||||
Reference in New Issue
Block a user