Skip to content

Instantly share code, notes, and snippets.

@crosbymichael
Created March 16, 2014 00:41
Show Gist options
  • Save crosbymichael/9576438 to your computer and use it in GitHub Desktop.
Save crosbymichael/9576438 to your computer and use it in GitHub Desktop.
package main
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"github.com/codegangsta/cli"
"github.com/mitchellh/goamz/aws"
"github.com/mitchellh/goamz/s3"
"io"
"log"
"os"
"path/filepath"
"time"
)
type Store []*Blob
type Blob struct {
Name string `json:"name"`
OriginalPath string `json:"original_path"`
Added time.Time `json:"time"`
Sha string `json:"sha"`
Size int64 `json:"size"`
}
func (s Store) Contains(hash string) bool {
for _, blob := range s {
if blob.Sha == hash {
return true
}
}
return false
}
func storePath() string {
home := os.Getenv("HOME")
return filepath.Join(home, ".blobdb")
}
func loadStore() (Store, error) {
f, err := os.Open(storePath())
if err != nil {
if os.IsNotExist(err) {
return Store{}, nil
}
return nil, err
}
defer f.Close()
var (
dec = json.NewDecoder(f)
store = Store{}
)
for {
var blob *Blob
if err := dec.Decode(&blob); err != nil {
if err == io.EOF {
break
}
return nil, err
}
store = append(store, blob)
}
return store, nil
}
func saveBlob(blob *Blob) error {
f, err := os.OpenFile(storePath(), os.O_CREATE|os.O_RDWR|os.O_APPEND, 0655)
if err != nil {
return err
}
defer f.Close()
return json.NewEncoder(f).Encode(blob)
}
func getBucket(name string) (*s3.Bucket, error) {
auth, err := aws.EnvAuth()
if err != nil {
return nil, err
}
var (
server = s3.New(auth, aws.USWest) // TODO: add region flag
bucket = server.Bucket(name)
)
return bucket, nil
}
func uploadAction(context *cli.Context) {
store, err := loadStore()
if err != nil {
log.Fatal(err)
}
path, err := filepath.Abs(context.Args().First())
if err != nil {
log.Fatal(err)
}
f, err := os.Open(path)
if err != nil {
log.Fatal(err)
}
defer f.Close()
hash, size, err := getHash(f)
if err != nil {
log.Fatal(err)
}
if store.Contains(hash) {
log.Fatalf("%s has already been uploaded\n", hash)
}
blob := &Blob{
Sha: hash,
Size: size,
OriginalPath: path,
Name: filepath.Base(path),
Added: time.Now(),
}
bucket, err := getBucket(context.String("bucket"))
if err != nil {
log.Fatal(err)
}
if err := bucket.PutReader(blob.Name, f, size, "blob", s3.BucketOwnerFull); err != nil {
log.Fatal(err)
}
if err := saveBlob(blob); err != nil {
log.Fatal(err)
}
}
func getHash(f *os.File) (hash string, size int64, err error) {
h := sha256.New()
if size, err = io.Copy(h, f); err != nil {
return "", size, err
}
hash = hex.EncodeToString(h.Sum(nil))
f.Seek(0, 0)
return
}
func main() {
app := cli.NewApp()
app.Author = "crosbymichael"
app.Version = "0.1.0"
app.Name = "blob"
app.Action = uploadAction
app.Flags = []cli.Flag{
cli.StringFlag{"bucket", "", "s3 bucket name"},
}
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment