Skip to content

Instantly share code, notes, and snippets.

@markbates
Last active November 1, 2018 18:34
Show Gist options
  • Save markbates/93f8bd139997b1273aad4bf59ab6d6f9 to your computer and use it in GitHub Desktop.
Save markbates/93f8bd139997b1273aad4bf59ab6d6f9 to your computer and use it in GitHub Desktop.
store and resolver implementation using s3 for Packr v2
package main
import (
"fmt"
"net/http"
_ "github.com/gobuffalo/buffalo"
"github.com/gobuffalo/packr/v2"
"github.com/markbates/s3packr/s3packr"
)
func main() {
box := packr.New("my templates", "../mysite/templates")
box.DefaultResolver = s3packr.NewResolver()
http.Handle("/", http.FileServer(box))
fmt.Println("listening on :3000")
http.ListenAndServe(":3000", nil)
}
package main
import (
"log"
"os"
"github.com/gobuffalo/logger"
"github.com/gobuffalo/packr/v2/jam/parser"
"github.com/gobuffalo/packr/v2/plog"
"github.com/markbates/s3packr/s3packr"
)
func main() {
plog.Logger = logger.New(logger.DebugLevel)
paths := os.Args[1:]
if len(paths) == 0 {
paths = []string{"."}
}
ps, err := parser.NewFromRoots(paths, &parser.RootsOptions{})
if err != nil {
log.Fatal(err)
}
boxes, err := ps.Run()
if err != nil {
log.Fatal(err)
}
for _, box := range boxes {
s3 := s3packr.New(box)
if err := s3.Pack(box); err != nil {
log.Fatal(err)
}
}
}
package s3packr
import (
"context"
"github.com/gobuffalo/packr/v2/file"
"github.com/gobuffalo/packr/v2/file/resolver"
"github.com/google/go-cloud/blob"
"github.com/pkg/errors"
)
type Resolver struct {
*resolver.Disk
}
func NewResolver() resolver.Resolver {
return Resolver{
Disk: &resolver.Disk{Root: "."},
}
}
func (r Resolver) Resolve(box string, path string) (file.File, error) {
var f file.File
key := Key(box + path)
withBucket(func(ctx context.Context, buck *blob.Bucket) error {
r, err := buck.NewReader(ctx, key)
if err != nil {
return errors.WithStack(err)
}
defer r.Close()
f, err = file.NewFileR(path, r)
return err
})
if f != nil {
return f, nil
}
f, err := r.Disk.Resolve(box, path)
if err != nil {
return f, errors.WithStack(err)
}
return f, nil
}
package s3packr
import (
"crypto/sha1"
"fmt"
"io"
"path/filepath"
"strings"
)
func Key(s string) string {
h := sha1.New()
io.WriteString(h, strings.ToLower(s))
return fmt.Sprintf("%x%s", h.Sum(nil), filepath.Ext(s))
}
package s3packr
import (
"context"
"io"
"os"
"path/filepath"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/gobuffalo/envy"
"github.com/gobuffalo/packr/v2/jam/parser"
"github.com/gobuffalo/packr/v2/jam/store"
"github.com/gobuffalo/packr/v2/plog"
"github.com/google/go-cloud/blob"
"github.com/google/go-cloud/blob/s3blob"
"github.com/pkg/errors"
)
var _ store.Store = &S3Store{}
type S3Store struct {
*store.Disk
}
func New(box *parser.Box) *S3Store {
return &S3Store{
Disk: store.NewDisk(box.AbsPath, box.Package),
}
}
func (s *S3Store) Pack(box *parser.Box) error {
plog.Debug(s, "Pack", "box", box)
return filepath.Walk(box.AbsPath, func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
return nil
}
return s.upload(box.Name, path)
})
}
func (s *S3Store) upload(box string, path string) error {
return withBucket(func(ctx context.Context, buck *blob.Bucket) error {
w, err := buck.NewWriter(ctx, Key(box+path), &blob.WriterOptions{
ContentType: "application/octet-stream",
})
if err != nil {
return errors.WithStack(err)
}
defer w.Close()
f, err := os.Open(path)
if err != nil {
return errors.WithStack(err)
}
defer f.Close()
_, err = io.Copy(w, f)
if err != nil {
return errors.WithStack(err)
}
return nil
})
}
func withBucket(fn func(context.Context, *blob.Bucket) error) error {
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
key, err := envy.MustGet("S3_KEY")
if err != nil {
return errors.WithStack(err)
}
secret, err := envy.MustGet("S3_SECRET")
if err != nil {
return errors.WithStack(err)
}
config := aws.NewConfig()
config.Region = aws.String("us-east-1")
config.Credentials = credentials.NewStaticCredentialsFromCreds(credentials.Value{
AccessKeyID: key,
SecretAccessKey: secret,
})
sess, err := session.NewSession(config)
if err != nil {
return errors.WithStack(err)
}
buck, err := s3blob.OpenBucket(ctx, sess, "s3packr-demo")
if err != nil {
return errors.WithStack(err)
}
return fn(ctx, buck)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment