1
0
Fork 0
mirror of https://github.com/Luzifer/share.git synced 2024-10-18 13:24:23 +00:00
share/main.go

137 lines
3.4 KiB
Go
Raw Normal View History

2017-12-02 14:25:54 +00:00
package main
//go:generate make pack
2017-12-02 14:25:54 +00:00
import (
"bytes"
"crypto/sha1"
"fmt"
"io"
2017-12-02 14:25:54 +00:00
"io/ioutil"
"mime"
"os"
"path"
"text/template"
"github.com/Luzifer/rconfig"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
log "github.com/sirupsen/logrus"
)
var (
cfg = struct {
BaseURL string `flag:"base-url" default:"" description:"URL to prepend before filename"`
2017-12-02 14:25:54 +00:00
BasePath string `flag:"base-path" default:"file/{{ printf \"%.2s\" .Hash }}/{{.Hash}}" description:"Path to upload the file to"`
Bootstrap bool `flag:"bootstrap" default:"false" description:"Upload frontend files into bucket"`
2017-12-02 14:25:54 +00:00
Bucket string `flag:"bucket" default:"" description:"S3 bucket to upload files to" validate:"nonzero"`
VersionAndExit bool `flag:"version" default:"false" description:"Prints current version and exits"`
}{}
version = "dev"
)
func init() {
if err := rconfig.ParseAndValidate(&cfg); err != nil {
log.Fatalf("Unable to parse commandline options: %s", err)
}
if cfg.VersionAndExit {
fmt.Printf("share %s\n", version)
os.Exit(0)
}
}
func main() {
if cfg.Bootstrap {
for _, asset := range []string{"index.html", "app.js"} {
if _, err := executeUpload(asset, asset, bytes.NewReader(MustAsset("frontend/"+asset))); err != nil {
log.WithError(err).Fatalf("Unable to upload bootstrap asset %q", asset)
}
}
log.Info("Bucket bootstrap finished: Frontend uploaded.")
return
}
2017-12-02 14:25:54 +00:00
if len(rconfig.Args()) == 1 {
log.Fatalf("Usage: share <file to upload>")
}
if cfg.BaseURL == "" {
log.Error("No BaseURL configured, output will be no complete URL")
2017-12-02 15:34:21 +00:00
}
inFile := rconfig.Args()[1]
2017-12-02 14:25:54 +00:00
inFileHandle, err := os.Open(inFile)
if err != nil {
log.WithError(err).Fatal("Unable to open source file")
}
upFile, err := calculateUploadFilename(inFile)
if err != nil {
log.WithError(err).Fatal("Unable to calculate upload filename")
}
url, err := executeUpload(inFile, upFile, inFileHandle)
if err != nil {
log.WithError(err).Fatal("Failed to upload file")
}
fmt.Println(url)
}
func calculateUploadFilename(inFile string) (string, error) {
upFile := path.Join(cfg.BasePath, path.Base(inFile))
2017-12-02 14:25:54 +00:00
fileHash, err := hashFile(inFile)
if err != nil {
return "", err
2017-12-02 14:25:54 +00:00
}
return executeTemplate(upFile, map[string]interface{}{
2017-12-02 14:25:54 +00:00
"Hash": fileHash,
})
}
func executeUpload(inFile, upFile string, inFileHandle io.ReadSeeker) (string, error) {
mimeType := mime.TypeByExtension(path.Ext(inFile))
if mimeType == "" {
mimeType = "application/octet-stream"
2017-12-02 14:25:54 +00:00
}
log.Debugf("Uploading %q to %q with type %q", inFile, upFile, mimeType)
2017-12-02 14:25:54 +00:00
sess := session.Must(session.NewSession())
svc := s3.New(sess)
if _, err := svc.PutObject(&s3.PutObjectInput{
Body: inFileHandle,
Bucket: aws.String(cfg.Bucket),
2017-12-02 15:34:21 +00:00
ContentType: aws.String(mimeType),
2017-12-02 14:25:54 +00:00
Key: aws.String(upFile),
}); err != nil {
return "", err
2017-12-02 14:25:54 +00:00
}
return fmt.Sprintf("%s%s", cfg.BaseURL, upFile), nil
2017-12-02 14:25:54 +00:00
}
func hashFile(inFile string) (string, error) {
data, err := ioutil.ReadFile(inFile)
if err != nil {
return "", err
}
sum1 := sha1.Sum(data)
return fmt.Sprintf("%x", sum1), nil
}
func executeTemplate(tplStr string, vars map[string]interface{}) (string, error) {
tpl, err := template.New("basepath").Parse(tplStr)
if err != nil {
return "", err
}
buf := new(bytes.Buffer)
err = tpl.Execute(buf, vars)
return buf.String(), err
}