blob: 630f5dfe62b927c73459591dd1c7afdd9d30ebc5 [file] [log] [blame]
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"archive/zip"
"bytes"
"context"
"crypto/md5"
"fmt"
"io"
"log"
"os"
"path/filepath"
"strings"
"sync"
"time"
"cloud.google.com/go/storage"
)
var (
ctx = context.Background()
client *storage.Client
bucket *storage.BucketHandle
)
var cache struct {
sync.Mutex
entry map[string]*cacheEntry
}
type cacheEntry struct {
sync.Mutex
expire time.Time
md5 []byte
}
func init() {
var err error
client, err = storage.NewClient(ctx)
if err != nil {
log.Fatal(err)
}
bucket = client.Bucket("vcs-test")
cache.entry = map[string]*cacheEntry{}
}
func loadFS(dir1, dir2 string, force bool) {
name := dir1 + "/" + dir2
defer func() {
if err := recover(); err != nil {
log.Printf("%s: %v", name, err)
}
}()
check := func(err error) {
if err != nil {
panic(err)
}
}
check(os.MkdirAll(filepath.Join(*dir, dir1), 0777))
cache.Lock()
entry := cache.entry[name]
if entry == nil {
entry = new(cacheEntry)
cache.entry[name] = entry
}
cache.Unlock()
entry.Lock()
defer entry.Unlock()
if time.Now().Before(entry.expire) && !force {
return
}
entry.expire = time.Now().Add(5 * time.Minute)
obj := bucket.Object(name + ".zip")
attrs, err := obj.Attrs(ctx)
check(err)
if bytes.Equal(attrs.MD5, entry.md5) {
return
}
r, err := obj.NewReader(ctx)
check(err)
defer r.Close()
zipFile := filepath.Join(*dir, name+".zip")
zf, err := os.Create(zipFile)
check(err)
h := md5.New()
_, err = io.Copy(io.MultiWriter(zf, h), r)
check(zf.Close())
check(err)
sum := h.Sum(nil)
if !bytes.Equal(attrs.MD5, sum) {
panic(fmt.Sprintf("load: unexpected md5 %x != %x", sum, attrs.MD5))
}
zf, err = os.Open(zipFile)
check(err)
info, err := zf.Stat()
check(err)
zr, err := zip.NewReader(zf, info.Size())
check(err)
tmp := filepath.Join(*dir, dir1+"/_"+dir2)
check(os.RemoveAll(tmp))
check(os.MkdirAll(tmp, 0777))
for _, f := range zr.File {
if strings.HasSuffix(f.Name, "/") {
check(os.MkdirAll(filepath.Join(tmp, f.Name), 0777))
continue
}
w, err := os.Create(filepath.Join(tmp, f.Name))
check(err)
r, err := f.Open()
check(err)
_, err = io.Copy(w, r)
check(err)
check(w.Close())
}
real := filepath.Join(*dir, dir1+"/"+dir2)
check(os.RemoveAll(real))
check(os.Rename(tmp, real))
entry.md5 = sum
}