<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
)

// Build release binaries according to the supplied settings, returning the
// path to a directory containing exactly the output binaries.
func buildBinaries(
	version string,
	commit string,
	osys string,
	arch string) (dir string, err error) {
	log.Printf("Building %s at %s for %s (%s).", version, commit, osys, arch)
	// Create a directory to hold our outputs. Kill it if we later return in
	// error.
	dir, err = ioutil.TempDir("", "build_release_binaries")
	if err != nil {
		err = fmt.Errorf("TempDir: %v", err)
		return
	}

	defer func() {
		if err != nil {
			os.RemoveAll(dir)
		}
	}()

	// Create another directory to become GOPATH for our build below.
	gopath, err := ioutil.TempDir("", "build_release_gopath")
	if err != nil {
		err = fmt.Errorf("TempDir: %v", err)
		return
	}

	defer os.RemoveAll(gopath)

	// Create a directory to store the source code.
	gitDir := path.Join(gopath, "src/github.com/googlecloudplatform/gcsfuse")
	err = os.MkdirAll(gitDir, 0700)
	if err != nil {
		err = fmt.Errorf("MkdirAll: %v", err)
		return
	}

	// Clone the source code into that directory.
	log.Printf("Cloning into %s", gitDir)

	cmd := exec.Command(
		"git",
		"clone",
		"https://github.com/GoogleCloudPlatform/gcsfuse.git",
		gitDir)

	output, err := cmd.CombinedOutput()
	if err != nil {
		err = fmt.Errorf("Cloning: %v\nOutput:\n%s", err, output)
		return
	}

	// Overwrite version.go with a file containing the appropriate constant.
	versionContents := fmt.Sprintf(
		"package main\nconst gcsfuseVersion = \"%s (commit %s)\"",
		version,
		commit)

	err = ioutil.WriteFile(
		path.Join(gitDir, "version.go"),
		[]byte(versionContents),
		0400)

	if err != nil {
		err = fmt.Errorf("WriteFile: %v", err)
		return
	}

	// Build the binaries.
	binaries := []string{
		"github.com/googlecloudplatform/gcsfuse",
		"github.com/googlecloudplatform/gcsfuse/gcsfuse_mount_helper",
	}

	for _, bin := range binaries {
		log.Printf("Building %s", bin)

		cmd = exec.Command(
			"go",
			"build",
			"-o",
			path.Join(dir, path.Base(bin)),
			bin)

		cmd.Env = []string{
			"GO15VENDOREXPERIMENT=1",
			fmt.Sprintf("GOPATH=%s", gopath),
			fmt.Sprintf("GOOS=%s", osys),
			fmt.Sprintf("GOARCH=%s", arch),
		}

		output, err = cmd.CombinedOutput()
		if err != nil {
			err = fmt.Errorf("Building %s: %v\nOutput:\n%s", bin, err, output)
			return
		}
	}

	return
}
<commit_msg>Don't forget to check out the appropriate commit.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
)

// Build release binaries according to the supplied settings, returning the
// path to a directory containing exactly the output binaries.
func buildBinaries(
	version string,
	commit string,
	osys string,
	arch string) (dir string, err error) {
	log.Printf("Building %s at %s for %s (%s).", version, commit, osys, arch)
	// Create a directory to hold our outputs. Kill it if we later return in
	// error.
	dir, err = ioutil.TempDir("", "build_release_binaries")
	if err != nil {
		err = fmt.Errorf("TempDir: %v", err)
		return
	}

	defer func() {
		if err != nil {
			os.RemoveAll(dir)
		}
	}()

	// Create another directory to become GOPATH for our build below.
	gopath, err := ioutil.TempDir("", "build_release_gopath")
	if err != nil {
		err = fmt.Errorf("TempDir: %v", err)
		return
	}

	defer os.RemoveAll(gopath)

	// Create a directory to store the source code.
	gitDir := path.Join(gopath, "src/github.com/googlecloudplatform/gcsfuse")
	err = os.MkdirAll(gitDir, 0700)
	if err != nil {
		err = fmt.Errorf("MkdirAll: %v", err)
		return
	}

	// Clone the source code into that directory.
	log.Printf("Cloning into %s", gitDir)

	cmd := exec.Command(
		"git",
		"clone",
		"https://github.com/GoogleCloudPlatform/gcsfuse.git",
		gitDir)

	output, err := cmd.CombinedOutput()
	if err != nil {
		err = fmt.Errorf("Cloning: %v\nOutput:\n%s", err, output)
		return
	}

	// Check out the appropriate commit.
	cmd = exec.Command("git", "checkout", commit)
	cmd.Dir = gitDir

	output, err = cmd.CombinedOutput()
	if err != nil {
		err = fmt.Errorf("git checkout: %v\nOutput:\n%s", err, output)
		return
	}

	// Overwrite version.go with a file containing the appropriate constant.
	versionContents := fmt.Sprintf(
		"package main\nconst gcsfuseVersion = \"%s (commit %s)\"",
		version,
		commit)

	err = ioutil.WriteFile(
		path.Join(gitDir, "version.go"),
		[]byte(versionContents),
		0400)

	if err != nil {
		err = fmt.Errorf("WriteFile: %v", err)
		return
	}

	// Build the binaries.
	binaries := []string{
		"github.com/googlecloudplatform/gcsfuse",
		"github.com/googlecloudplatform/gcsfuse/gcsfuse_mount_helper",
	}

	for _, bin := range binaries {
		log.Printf("Building %s", bin)

		cmd = exec.Command(
			"go",
			"build",
			"-o",
			path.Join(dir, path.Base(bin)),
			bin)

		cmd.Env = []string{
			"GO15VENDOREXPERIMENT=1",
			fmt.Sprintf("GOPATH=%s", gopath),
			fmt.Sprintf("GOOS=%s", osys),
			fmt.Sprintf("GOARCH=%s", arch),
		}

		output, err = cmd.CombinedOutput()
		if err != nil {
			err = fmt.Errorf("Building %s: %v\nOutput:\n%s", bin, err, output)
			return
		}
	}

	return
}
<|endoftext|>


<commit_before>// Load a wikipedia dump into CouchDB
package main

import (
	"compress/bzip2"
	"log"
	"os"
	"strings"
	"sync"
	"time"

	"code.google.com/p/dsallings-couch-go"
	"github.com/dustin/go-humanize"
	"github.com/dustin/go-wikiparse"
)

var wg sync.WaitGroup

type Geo struct {
	Geometry struct {
		Type        string    `json:"type"`
		Coordinates []float64 `json:"coordinates"`
	}           `json:"geometry"`
	Type string `json:"type"`
}

type Article struct {
	ID      string `json:"_id"`
	Rev     string `json:"_rev"`
	RevInfo struct {
		ID            uint64 `json:"id"`
		Timestamp     string `json:"timestamp"`
		Contributor   string `json:"contributor"`
		ContributorId uint64 `json:"contributorid"`
		Comment       string `json:"comment"`
	}           `json:"revinfo"`
	Text string `json:"text"`
	Geo  *Geo   `json:"geo,omitempty"`
}

func escapeTitle(in string) string {
	return strings.Replace(strings.Replace(in, "/", "%2f", -1),
		"+", "%2b", -1)
}

func resolveConflict(db *couch.Database, a *Article) {
	log.Printf("Resolving conflict on %s", a.ID)
	var prev Article
	err := db.Retrieve(a.ID, &prev)
	if err != nil {
		log.Printf("  Error retrieving existing %v: %v", a.ID, err)
		return
	}
	if prev.Rev == "" {
		log.Printf("Got no rev from %v", a.ID)
		return
	}
	if a.RevInfo.Timestamp > prev.RevInfo.Timestamp {
		log.Printf("  This one is newer...replacing %s.", prev.Rev)
		_, err = db.EditWith(a, a.ID, prev.Rev)
		if err != nil {
			log.Printf("  Error updating %v: %v", prev.ID, err)
		}
	}
}

func doPage(db *couch.Database, p *wikiparse.Page) {
	defer wg.Done()
	article := Article{}
	gl, err := wikiparse.ParseCoords(p.Revision.Text)
	if err == nil {
		article.Geo = &Geo{Type: "Feature"}
		article.Geo.Geometry.Type = "Point"
		article.Geo.Geometry.Coordinates = []float64{gl.Lon, gl.Lat}
	}
	article.RevInfo.ID = p.Revision.ID
	article.RevInfo.Timestamp = p.Revision.Timestamp
	article.RevInfo.Contributor = p.Revision.Contributor.Username
	article.RevInfo.ContributorId = p.Revision.Contributor.ID
	article.RevInfo.Comment = p.Revision.Comment
	article.Text = p.Revision.Text
	article.ID = escapeTitle(p.Title)

	_, _, err = db.Insert(&article)
	httpe, isHttpError := err.(*couch.HttpError)
	switch {
	case err == nil:
		// yay
	case isHttpError && httpe.Status == 409:
		resolveConflict(db, &article)
	default:
		log.Printf("Error inserting %#v: %v", article, err)
	}
}

func pageHandler(db couch.Database, ch <-chan *wikiparse.Page) {
	for p := range ch {
		doPage(&db, p)
	}
}

func main() {
	filename, dburl := os.Args[1], os.Args[2]

	db, err := couch.Connect(dburl)
	if err != nil {
		log.Fatal("Error connecting to couchdb: %v", err)
	}

	f, err := os.Open(filename)
	if err != nil {
		log.Fatalf("Error opening file: %v", err)
	}
	defer f.Close()

	z := bzip2.NewReader(f)

	p, err := wikiparse.NewParser(z)
	if err != nil {
		log.Fatalf("Error setting up new page parser:  %v", err)
	}

	log.Printf("Got site info:  %+v", p.SiteInfo)

	ch := make(chan *wikiparse.Page, 1000)

	for i := 0; i < 20; i++ {
		go pageHandler(db, ch)
	}

	pages := int64(0)
	start := time.Now()
	prev := start
	reportfreq := int64(1000)
	for err == nil {
		var page *wikiparse.Page
		page, err = p.Next()
		if err == nil {
			wg.Add(1)
			ch <- page
		}

		pages++
		if pages%reportfreq == 0 {
			now := time.Now()
			d := now.Sub(prev)
			log.Printf("Processed %s pages total (%.2f/s)",
				humanize.Comma(pages), float64(reportfreq)/d.Seconds())
			prev = now
		}
	}
	wg.Wait()
	close(ch)
	log.Printf("Ended with err after %v:  %v after %s pages",
		time.Now().Sub(start), err, humanize.Comma(pages))

}
<commit_msg>Escape on the get as well as the edit.<commit_after>// Load a wikipedia dump into CouchDB
package main

import (
	"compress/bzip2"
	"log"
	"os"
	"strings"
	"sync"
	"time"

	"code.google.com/p/dsallings-couch-go"
	"github.com/dustin/go-humanize"
	"github.com/dustin/go-wikiparse"
)

var wg sync.WaitGroup

type Geo struct {
	Geometry struct {
		Type        string    `json:"type"`
		Coordinates []float64 `json:"coordinates"`
	}           `json:"geometry"`
	Type string `json:"type"`
}

type Article struct {
	ID      string `json:"_id"`
	Rev     string `json:"_rev"`
	RevInfo struct {
		ID            uint64 `json:"id"`
		Timestamp     string `json:"timestamp"`
		Contributor   string `json:"contributor"`
		ContributorId uint64 `json:"contributorid"`
		Comment       string `json:"comment"`
	}           `json:"revinfo"`
	Text string `json:"text"`
	Geo  *Geo   `json:"geo,omitempty"`
}

func escapeTitle(in string) string {
	return strings.Replace(strings.Replace(in, "/", "%2f", -1),
		"+", "%2b", -1)
}

func resolveConflict(db *couch.Database, a *Article) {
	log.Printf("Resolving conflict on %s", a.ID)
	var prev Article
	err := db.Retrieve(escapeTitle(a.ID), &prev)
	if err != nil {
		log.Printf("  Error retrieving existing %v: %v", a.ID, err)
		return
	}
	if prev.Rev == "" {
		log.Printf("Got no rev from %v", a.ID)
		return
	}
	if a.RevInfo.Timestamp > prev.RevInfo.Timestamp {
		log.Printf("  This one is newer...replacing %s.", prev.Rev)
		_, err = db.EditWith(a, a.ID, prev.Rev)
		if err != nil {
			log.Printf("  Error updating %v: %v", prev.ID, err)
		}
	}
}

func doPage(db *couch.Database, p *wikiparse.Page) {
	defer wg.Done()
	article := Article{}
	gl, err := wikiparse.ParseCoords(p.Revision.Text)
	if err == nil {
		article.Geo = &Geo{Type: "Feature"}
		article.Geo.Geometry.Type = "Point"
		article.Geo.Geometry.Coordinates = []float64{gl.Lon, gl.Lat}
	}
	article.RevInfo.ID = p.Revision.ID
	article.RevInfo.Timestamp = p.Revision.Timestamp
	article.RevInfo.Contributor = p.Revision.Contributor.Username
	article.RevInfo.ContributorId = p.Revision.Contributor.ID
	article.RevInfo.Comment = p.Revision.Comment
	article.Text = p.Revision.Text
	article.ID = escapeTitle(p.Title)

	_, _, err = db.Insert(&article)
	httpe, isHttpError := err.(*couch.HttpError)
	switch {
	case err == nil:
		// yay
	case isHttpError && httpe.Status == 409:
		resolveConflict(db, &article)
	default:
		log.Printf("Error inserting %#v: %v", article, err)
	}
}

func pageHandler(db couch.Database, ch <-chan *wikiparse.Page) {
	for p := range ch {
		doPage(&db, p)
	}
}

func main() {
	filename, dburl := os.Args[1], os.Args[2]

	db, err := couch.Connect(dburl)
	if err != nil {
		log.Fatal("Error connecting to couchdb: %v", err)
	}

	f, err := os.Open(filename)
	if err != nil {
		log.Fatalf("Error opening file: %v", err)
	}
	defer f.Close()

	z := bzip2.NewReader(f)

	p, err := wikiparse.NewParser(z)
	if err != nil {
		log.Fatalf("Error setting up new page parser:  %v", err)
	}

	log.Printf("Got site info:  %+v", p.SiteInfo)

	ch := make(chan *wikiparse.Page, 1000)

	for i := 0; i < 20; i++ {
		go pageHandler(db, ch)
	}

	pages := int64(0)
	start := time.Now()
	prev := start
	reportfreq := int64(1000)
	for err == nil {
		var page *wikiparse.Page
		page, err = p.Next()
		if err == nil {
			wg.Add(1)
			ch <- page
		}

		pages++
		if pages%reportfreq == 0 {
			now := time.Now()
			d := now.Sub(prev)
			log.Printf("Processed %s pages total (%.2f/s)",
				humanize.Comma(pages), float64(reportfreq)/d.Seconds())
			prev = now
		}
	}
	wg.Wait()
	close(ch)
	log.Printf("Ended with err after %v:  %v after %s pages",
		time.Now().Sub(start), err, humanize.Comma(pages))

}
<|endoftext|>


<commit_before>// Copyright 2018 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"flag"
	"fmt"
	"log"
	"path/filepath"
	"strings"
	"time"

	"github.com/coreos/etcd/etcdserver/etcdserverpb"
	"github.com/coreos/etcd/pkg/pbutil"
	"github.com/coreos/etcd/pkg/types"
	"github.com/coreos/etcd/raft/raftpb"
	"github.com/coreos/etcd/raftsnap"
	"github.com/coreos/etcd/wal"
	"github.com/coreos/etcd/wal/walpb"

	"go.uber.org/zap"
)

func main() {
	snapfile := flag.String("start-snap", "", "The base name of snapshot file to start dumping")
	index := flag.Uint64("start-index", 0, "The index to start dumping")
	entrytype := flag.String("entry-type", "", `If set, filters output by entry type. Must be one or more than one of:
	ConfigChange, Normal, Request, InternalRaftRequest,
	IRRRange, IRRPut, IRRDeleteRange, IRRTxn,
	IRRCompaction, IRRLeaseGrant, IRRLeaseRevoke`)

	flag.Parse()

	if len(flag.Args()) != 1 {
		log.Fatalf("Must provide data-dir argument (got %+v)", flag.Args())
	}
	dataDir := flag.Args()[0]

	if *snapfile != "" && *index != 0 {
		log.Fatal("start-snap and start-index flags cannot be used together.")
	}

	var (
		walsnap  walpb.Snapshot
		snapshot *raftpb.Snapshot
		err      error
	)

	isIndex := *index != 0

	if isIndex {
		fmt.Printf("Start dumping log entries from index %d.\n", *index)
		walsnap.Index = *index
	} else {
		if *snapfile == "" {
			ss := raftsnap.New(zap.NewExample(), snapDir(dataDir))
			snapshot, err = ss.Load()
		} else {
			snapshot, err = raftsnap.Read(filepath.Join(snapDir(dataDir), *snapfile))
		}

		switch err {
		case nil:
			walsnap.Index, walsnap.Term = snapshot.Metadata.Index, snapshot.Metadata.Term
			nodes := genIDSlice(snapshot.Metadata.ConfState.Nodes)
			fmt.Printf("Snapshot:\nterm=%d index=%d nodes=%s\n",
				walsnap.Term, walsnap.Index, nodes)
		case raftsnap.ErrNoSnapshot:
			fmt.Printf("Snapshot:\nempty\n")
		default:
			log.Fatalf("Failed loading snapshot: %v", err)
		}
		fmt.Println("Start dupmping log entries from snapshot.")
	}

	w, err := wal.OpenForRead(zap.NewExample(), walDir(dataDir), walsnap)
	if err != nil {
		log.Fatalf("Failed opening WAL: %v", err)
	}
	wmetadata, state, ents, err := w.ReadAll()
	w.Close()
	if err != nil && (!isIndex || err != wal.ErrSnapshotNotFound) {
		log.Fatalf("Failed reading WAL: %v", err)
	}
	id, cid := parseWALMetadata(wmetadata)
	vid := types.ID(state.Vote)
	fmt.Printf("WAL metadata:\nnodeID=%s clusterID=%s term=%d commitIndex=%d vote=%s\n",
		id, cid, state.Term, state.Commit, vid)

	fmt.Printf("WAL entries:\n")
	fmt.Printf("lastIndex=%d\n", ents[len(ents)-1].Index)
	fmt.Printf("%4s\t%10s\ttype\tdata\n", "term", "index")
	listEntriesType(*entrytype, ents)
}

func walDir(dataDir string) string { return filepath.Join(dataDir, "member", "wal") }

func snapDir(dataDir string) string { return filepath.Join(dataDir, "member", "snap") }

func parseWALMetadata(b []byte) (id, cid types.ID) {
	var metadata etcdserverpb.Metadata
	pbutil.MustUnmarshal(&metadata, b)
	id = types.ID(metadata.NodeID)
	cid = types.ID(metadata.ClusterID)
	return id, cid
}

func genIDSlice(a []uint64) []types.ID {
	ids := make([]types.ID, len(a))
	for i, id := range a {
		ids[i] = types.ID(id)
	}
	return ids
}

// excerpt replaces middle part with ellipsis and returns a double-quoted
// string safely escaped with Go syntax.
func excerpt(str string, pre, suf int) string {
	if pre+suf > len(str) {
		return fmt.Sprintf("%q", str)
	}
	return fmt.Sprintf("%q...%q", str[:pre], str[len(str)-suf:])
}

type EntryFilter func(e raftpb.Entry) (bool, string)

// The 9 pass functions below takes the raftpb.Entry and return if the entry should be printed and the type of entry,
// the type of the entry will used in the following print function
func passConfChange(entry raftpb.Entry) (bool, string) {
	return entry.Type == raftpb.EntryConfChange, "ConfigChange"
}

func passInternalRaftRequest(entry raftpb.Entry) (bool, string) {
	var rr etcdserverpb.InternalRaftRequest
	return entry.Type == raftpb.EntryNormal && rr.Unmarshal(entry.Data) == nil, "InternalRaftRequest"
}

func passUnknownNormal(entry raftpb.Entry) (bool, string) {
	var rr1 etcdserverpb.Request
	var rr2 etcdserverpb.InternalRaftRequest
	return (entry.Type == raftpb.EntryNormal) && (rr1.Unmarshal(entry.Data) != nil) && (rr2.Unmarshal(entry.Data) != nil), "UnknownNormal"
}

func passIRRRange(entry raftpb.Entry) (bool, string) {
	var rr etcdserverpb.InternalRaftRequest
	return entry.Type == raftpb.EntryNormal && rr.Unmarshal(entry.Data) == nil && rr.Range != nil, "InternalRaftRequest"
}

func passIRRPut(entry raftpb.Entry) (bool, string) {
	var rr etcdserverpb.InternalRaftRequest
	return entry.Type == raftpb.EntryNormal && rr.Unmarshal(entry.Data) == nil && rr.Put != nil, "InternalRaftRequest"
}

func passIRRDeleteRange(entry raftpb.Entry) (bool, string) {
	var rr etcdserverpb.InternalRaftRequest
	return entry.Type == raftpb.EntryNormal && rr.Unmarshal(entry.Data) == nil && rr.DeleteRange != nil, "InternalRaftRequest"
}

func passIRRTxn(entry raftpb.Entry) (bool, string) {
	var rr etcdserverpb.InternalRaftRequest
	return entry.Type == raftpb.EntryNormal && rr.Unmarshal(entry.Data) == nil && rr.Txn != nil, "InternalRaftRequest"
}

func passIRRCompaction(entry raftpb.Entry) (bool, string) {
	var rr etcdserverpb.InternalRaftRequest
	return entry.Type == raftpb.EntryNormal && rr.Unmarshal(entry.Data) == nil && rr.Compaction != nil, "InternalRaftRequest"
}

func passIRRLeaseGrant(entry raftpb.Entry) (bool, string) {
	var rr etcdserverpb.InternalRaftRequest
	return entry.Type == raftpb.EntryNormal && rr.Unmarshal(entry.Data) == nil && rr.LeaseGrant != nil, "InternalRaftRequest"
}

func passIRRLeaseRevoke(entry raftpb.Entry) (bool, string) {
	var rr etcdserverpb.InternalRaftRequest
	return entry.Type == raftpb.EntryNormal && rr.Unmarshal(entry.Data) == nil && rr.LeaseRevoke != nil, "InternalRaftRequest"
}

func passRequest(entry raftpb.Entry) (bool, string) {
	var rr1 etcdserverpb.Request
	var rr2 etcdserverpb.InternalRaftRequest
	return entry.Type == raftpb.EntryNormal && rr1.Unmarshal(entry.Data) == nil && rr2.Unmarshal(entry.Data) != nil, "Request"
}

type EntryPrinter func(e raftpb.Entry)

// The 4 print functions below print the entry format based on there types

// printInternalRaftRequest is used to print entry information for IRRRange, IRRPut,
// IRRDeleteRange and IRRTxn entries
func printInternalRaftRequest(entry raftpb.Entry) {
	var rr etcdserverpb.InternalRaftRequest
	if err := rr.Unmarshal(entry.Data); err == nil {
		fmt.Printf("%4d\t%10d\tnorm\t%s\n", entry.Term, entry.Index, rr.String())
	}
}

func printUnknownNormal(entry raftpb.Entry) {
	fmt.Printf("%4d\t%10d\tnorm\t???\n", entry.Term, entry.Index)
}

func printConfChange(entry raftpb.Entry) {
	fmt.Printf("%4d\t%10d", entry.Term, entry.Index)
	fmt.Printf("\tconf")
	var r raftpb.ConfChange
	if err := r.Unmarshal(entry.Data); err != nil {
		fmt.Printf("\t???\n")
	} else {
		fmt.Printf("\tmethod=%s id=%s\n", r.Type, types.ID(r.NodeID))
	}
}

func printRequest(entry raftpb.Entry) {
	var r etcdserverpb.Request
	if err := r.Unmarshal(entry.Data); err == nil {
		fmt.Printf("%4d\t%10d\tnorm", entry.Term, entry.Index)
		switch r.Method {
		case "":
			fmt.Printf("\tnoop\n")
		case "SYNC":
			fmt.Printf("\tmethod=SYNC time=%q\n", time.Unix(0, r.Time))
		case "QGET", "DELETE":
			fmt.Printf("\tmethod=%s path=%s\n", r.Method, excerpt(r.Path, 64, 64))
		default:
			fmt.Printf("\tmethod=%s path=%s val=%s\n", r.Method, excerpt(r.Path, 64, 64), excerpt(r.Val, 128, 0))
		}
	}
}

// evaluateEntrytypeFlag evaluates entry-type flag and choose proper filter/filters to filter entries
func evaluateEntrytypeFlag(entrytype string) []EntryFilter {
	var entrytypelist []string
	if entrytype != "" {
		entrytypelist = strings.Split(entrytype, ",")
	}

	validRequest := map[string][]EntryFilter{"ConfigChange": {passConfChange},
		"Normal":              {passInternalRaftRequest, passRequest, passUnknownNormal},
		"Request":             {passRequest},
		"InternalRaftRequest": {passInternalRaftRequest},
		"IRRRange":            {passIRRRange},
		"IRRPut":              {passIRRPut},
		"IRRDeleteRange":      {passIRRDeleteRange},
		"IRRTxn":              {passIRRTxn},
		"IRRCompaction":       {passIRRCompaction},
		"IRRLeaseGrant":       {passIRRLeaseGrant},
		"IRRLeaseRevoke":      {passIRRLeaseRevoke},
	}
	filters := make([]EntryFilter, 0)
	if len(entrytypelist) == 0 {
		filters = append(filters, passInternalRaftRequest)
		filters = append(filters, passRequest)
		filters = append(filters, passUnknownNormal)
		filters = append(filters, passConfChange)
	}
	for _, et := range entrytypelist {
		if f, ok := validRequest[et]; ok {
			filters = append(filters, f...)
		} else {
			log.Printf(`[%+v] is not a valid entry-type, ignored.
Please set entry-type to one or more of the following:
ConfigChange, Normal, Request, InternalRaftRequest,
IRRRange, IRRPut, IRRDeleteRange, IRRTxn,
IRRCompaction, IRRLeaseGrant, IRRLeaseRevoke`, et)
		}
	}

	return filters
}

//  listEntriesType filters and prints entries based on the entry-type flag,
func listEntriesType(entrytype string, ents []raftpb.Entry) {
	entryFilters := evaluateEntrytypeFlag(entrytype)
	printerMap := map[string]EntryPrinter{"InternalRaftRequest": printInternalRaftRequest,
		"Request":       printRequest,
		"ConfigChange":  printConfChange,
		"UnknownNormal": printUnknownNormal}
	cnt := 0
	for _, e := range ents {
		passed := false
		currtype := ""
		for _, filter := range entryFilters {
			passed, currtype = filter(e)
			if passed {
				cnt++
				break
			}
		}
		if passed {
			printer := printerMap[currtype]
			printer(e)
		}
	}
	fmt.Printf("\nEntry types (%s) count is : %d", entrytype, cnt)
}
<commit_msg>tools/etcd-dump-logs: pass zap logger to raftsnap<commit_after>// Copyright 2018 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"flag"
	"fmt"
	"log"
	"path/filepath"
	"strings"
	"time"

	"github.com/coreos/etcd/etcdserver/etcdserverpb"
	"github.com/coreos/etcd/pkg/pbutil"
	"github.com/coreos/etcd/pkg/types"
	"github.com/coreos/etcd/raft/raftpb"
	"github.com/coreos/etcd/raftsnap"
	"github.com/coreos/etcd/wal"
	"github.com/coreos/etcd/wal/walpb"

	"go.uber.org/zap"
)

func main() {
	snapfile := flag.String("start-snap", "", "The base name of snapshot file to start dumping")
	index := flag.Uint64("start-index", 0, "The index to start dumping")
	entrytype := flag.String("entry-type", "", `If set, filters output by entry type. Must be one or more than one of:
	ConfigChange, Normal, Request, InternalRaftRequest,
	IRRRange, IRRPut, IRRDeleteRange, IRRTxn,
	IRRCompaction, IRRLeaseGrant, IRRLeaseRevoke`)

	flag.Parse()

	if len(flag.Args()) != 1 {
		log.Fatalf("Must provide data-dir argument (got %+v)", flag.Args())
	}
	dataDir := flag.Args()[0]

	if *snapfile != "" && *index != 0 {
		log.Fatal("start-snap and start-index flags cannot be used together.")
	}

	var (
		walsnap  walpb.Snapshot
		snapshot *raftpb.Snapshot
		err      error
	)

	isIndex := *index != 0

	if isIndex {
		fmt.Printf("Start dumping log entries from index %d.\n", *index)
		walsnap.Index = *index
	} else {
		if *snapfile == "" {
			ss := raftsnap.New(zap.NewExample(), snapDir(dataDir))
			snapshot, err = ss.Load()
		} else {
			snapshot, err = raftsnap.Read(zap.NewExample(), filepath.Join(snapDir(dataDir), *snapfile))
		}

		switch err {
		case nil:
			walsnap.Index, walsnap.Term = snapshot.Metadata.Index, snapshot.Metadata.Term
			nodes := genIDSlice(snapshot.Metadata.ConfState.Nodes)
			fmt.Printf("Snapshot:\nterm=%d index=%d nodes=%s\n",
				walsnap.Term, walsnap.Index, nodes)
		case raftsnap.ErrNoSnapshot:
			fmt.Printf("Snapshot:\nempty\n")
		default:
			log.Fatalf("Failed loading snapshot: %v", err)
		}
		fmt.Println("Start dupmping log entries from snapshot.")
	}

	w, err := wal.OpenForRead(zap.NewExample(), walDir(dataDir), walsnap)
	if err != nil {
		log.Fatalf("Failed opening WAL: %v", err)
	}
	wmetadata, state, ents, err := w.ReadAll()
	w.Close()
	if err != nil && (!isIndex || err != wal.ErrSnapshotNotFound) {
		log.Fatalf("Failed reading WAL: %v", err)
	}
	id, cid := parseWALMetadata(wmetadata)
	vid := types.ID(state.Vote)
	fmt.Printf("WAL metadata:\nnodeID=%s clusterID=%s term=%d commitIndex=%d vote=%s\n",
		id, cid, state.Term, state.Commit, vid)

	fmt.Printf("WAL entries:\n")
	fmt.Printf("lastIndex=%d\n", ents[len(ents)-1].Index)
	fmt.Printf("%4s\t%10s\ttype\tdata\n", "term", "index")
	listEntriesType(*entrytype, ents)
}

func walDir(dataDir string) string { return filepath.Join(dataDir, "member", "wal") }

func snapDir(dataDir string) string { return filepath.Join(dataDir, "member", "snap") }

func parseWALMetadata(b []byte) (id, cid types.ID) {
	var metadata etcdserverpb.Metadata
	pbutil.MustUnmarshal(&metadata, b)
	id = types.ID(metadata.NodeID)
	cid = types.ID(metadata.ClusterID)
	return id, cid
}

func genIDSlice(a []uint64) []types.ID {
	ids := make([]types.ID, len(a))
	for i, id := range a {
		ids[i] = types.ID(id)
	}
	return ids
}

// excerpt replaces middle part with ellipsis and returns a double-quoted
// string safely escaped with Go syntax.
func excerpt(str string, pre, suf int) string {
	if pre+suf > len(str) {
		return fmt.Sprintf("%q", str)
	}
	return fmt.Sprintf("%q...%q", str[:pre], str[len(str)-suf:])
}

type EntryFilter func(e raftpb.Entry) (bool, string)

// The 9 pass functions below takes the raftpb.Entry and return if the entry should be printed and the type of entry,
// the type of the entry will used in the following print function
func passConfChange(entry raftpb.Entry) (bool, string) {
	return entry.Type == raftpb.EntryConfChange, "ConfigChange"
}

func passInternalRaftRequest(entry raftpb.Entry) (bool, string) {
	var rr etcdserverpb.InternalRaftRequest
	return entry.Type == raftpb.EntryNormal && rr.Unmarshal(entry.Data) == nil, "InternalRaftRequest"
}

func passUnknownNormal(entry raftpb.Entry) (bool, string) {
	var rr1 etcdserverpb.Request
	var rr2 etcdserverpb.InternalRaftRequest
	return (entry.Type == raftpb.EntryNormal) && (rr1.Unmarshal(entry.Data) != nil) && (rr2.Unmarshal(entry.Data) != nil), "UnknownNormal"
}

func passIRRRange(entry raftpb.Entry) (bool, string) {
	var rr etcdserverpb.InternalRaftRequest
	return entry.Type == raftpb.EntryNormal && rr.Unmarshal(entry.Data) == nil && rr.Range != nil, "InternalRaftRequest"
}

func passIRRPut(entry raftpb.Entry) (bool, string) {
	var rr etcdserverpb.InternalRaftRequest
	return entry.Type == raftpb.EntryNormal && rr.Unmarshal(entry.Data) == nil && rr.Put != nil, "InternalRaftRequest"
}

func passIRRDeleteRange(entry raftpb.Entry) (bool, string) {
	var rr etcdserverpb.InternalRaftRequest
	return entry.Type == raftpb.EntryNormal && rr.Unmarshal(entry.Data) == nil && rr.DeleteRange != nil, "InternalRaftRequest"
}

func passIRRTxn(entry raftpb.Entry) (bool, string) {
	var rr etcdserverpb.InternalRaftRequest
	return entry.Type == raftpb.EntryNormal && rr.Unmarshal(entry.Data) == nil && rr.Txn != nil, "InternalRaftRequest"
}

func passIRRCompaction(entry raftpb.Entry) (bool, string) {
	var rr etcdserverpb.InternalRaftRequest
	return entry.Type == raftpb.EntryNormal && rr.Unmarshal(entry.Data) == nil && rr.Compaction != nil, "InternalRaftRequest"
}

func passIRRLeaseGrant(entry raftpb.Entry) (bool, string) {
	var rr etcdserverpb.InternalRaftRequest
	return entry.Type == raftpb.EntryNormal && rr.Unmarshal(entry.Data) == nil && rr.LeaseGrant != nil, "InternalRaftRequest"
}

func passIRRLeaseRevoke(entry raftpb.Entry) (bool, string) {
	var rr etcdserverpb.InternalRaftRequest
	return entry.Type == raftpb.EntryNormal && rr.Unmarshal(entry.Data) == nil && rr.LeaseRevoke != nil, "InternalRaftRequest"
}

func passRequest(entry raftpb.Entry) (bool, string) {
	var rr1 etcdserverpb.Request
	var rr2 etcdserverpb.InternalRaftRequest
	return entry.Type == raftpb.EntryNormal && rr1.Unmarshal(entry.Data) == nil && rr2.Unmarshal(entry.Data) != nil, "Request"
}

type EntryPrinter func(e raftpb.Entry)

// The 4 print functions below print the entry format based on there types

// printInternalRaftRequest is used to print entry information for IRRRange, IRRPut,
// IRRDeleteRange and IRRTxn entries
func printInternalRaftRequest(entry raftpb.Entry) {
	var rr etcdserverpb.InternalRaftRequest
	if err := rr.Unmarshal(entry.Data); err == nil {
		fmt.Printf("%4d\t%10d\tnorm\t%s\n", entry.Term, entry.Index, rr.String())
	}
}

func printUnknownNormal(entry raftpb.Entry) {
	fmt.Printf("%4d\t%10d\tnorm\t???\n", entry.Term, entry.Index)
}

func printConfChange(entry raftpb.Entry) {
	fmt.Printf("%4d\t%10d", entry.Term, entry.Index)
	fmt.Printf("\tconf")
	var r raftpb.ConfChange
	if err := r.Unmarshal(entry.Data); err != nil {
		fmt.Printf("\t???\n")
	} else {
		fmt.Printf("\tmethod=%s id=%s\n", r.Type, types.ID(r.NodeID))
	}
}

func printRequest(entry raftpb.Entry) {
	var r etcdserverpb.Request
	if err := r.Unmarshal(entry.Data); err == nil {
		fmt.Printf("%4d\t%10d\tnorm", entry.Term, entry.Index)
		switch r.Method {
		case "":
			fmt.Printf("\tnoop\n")
		case "SYNC":
			fmt.Printf("\tmethod=SYNC time=%q\n", time.Unix(0, r.Time))
		case "QGET", "DELETE":
			fmt.Printf("\tmethod=%s path=%s\n", r.Method, excerpt(r.Path, 64, 64))
		default:
			fmt.Printf("\tmethod=%s path=%s val=%s\n", r.Method, excerpt(r.Path, 64, 64), excerpt(r.Val, 128, 0))
		}
	}
}

// evaluateEntrytypeFlag evaluates entry-type flag and choose proper filter/filters to filter entries
func evaluateEntrytypeFlag(entrytype string) []EntryFilter {
	var entrytypelist []string
	if entrytype != "" {
		entrytypelist = strings.Split(entrytype, ",")
	}

	validRequest := map[string][]EntryFilter{"ConfigChange": {passConfChange},
		"Normal":              {passInternalRaftRequest, passRequest, passUnknownNormal},
		"Request":             {passRequest},
		"InternalRaftRequest": {passInternalRaftRequest},
		"IRRRange":            {passIRRRange},
		"IRRPut":              {passIRRPut},
		"IRRDeleteRange":      {passIRRDeleteRange},
		"IRRTxn":              {passIRRTxn},
		"IRRCompaction":       {passIRRCompaction},
		"IRRLeaseGrant":       {passIRRLeaseGrant},
		"IRRLeaseRevoke":      {passIRRLeaseRevoke},
	}
	filters := make([]EntryFilter, 0)
	if len(entrytypelist) == 0 {
		filters = append(filters, passInternalRaftRequest)
		filters = append(filters, passRequest)
		filters = append(filters, passUnknownNormal)
		filters = append(filters, passConfChange)
	}
	for _, et := range entrytypelist {
		if f, ok := validRequest[et]; ok {
			filters = append(filters, f...)
		} else {
			log.Printf(`[%+v] is not a valid entry-type, ignored.
Please set entry-type to one or more of the following:
ConfigChange, Normal, Request, InternalRaftRequest,
IRRRange, IRRPut, IRRDeleteRange, IRRTxn,
IRRCompaction, IRRLeaseGrant, IRRLeaseRevoke`, et)
		}
	}

	return filters
}

//  listEntriesType filters and prints entries based on the entry-type flag,
func listEntriesType(entrytype string, ents []raftpb.Entry) {
	entryFilters := evaluateEntrytypeFlag(entrytype)
	printerMap := map[string]EntryPrinter{"InternalRaftRequest": printInternalRaftRequest,
		"Request":       printRequest,
		"ConfigChange":  printConfChange,
		"UnknownNormal": printUnknownNormal}
	cnt := 0
	for _, e := range ents {
		passed := false
		currtype := ""
		for _, filter := range entryFilters {
			passed, currtype = filter(e)
			if passed {
				cnt++
				break
			}
		}
		if passed {
			printer := printerMap[currtype]
			printer(e)
		}
	}
	fmt.Printf("\nEntry types (%s) count is : %d", entrytype, cnt)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"github.com/transloadit/go-sdk"
	"io/ioutil"
	"log"
	"os"
	"text/template"
)

var AuthKey string
var AuthSecret string
var Input string
var Output string
var TemplateId string
var TemplateFile string
var Watch bool
var Preserve bool
var Upstart bool

func init() {

	flag.StringVar(&AuthKey, "key", "", "Auth key")
	flag.StringVar(&AuthSecret, "secret", "", "Auth secret")
	flag.StringVar(&Input, "input", ".", "Input directory")
	flag.StringVar(&Output, "output", "", "Output directory")
	flag.StringVar(&TemplateId, "template", "", "Template's id to create assemblies with")
	flag.StringVar(&TemplateFile, "template-file", "", "Path to local file containing template JSON")
	flag.BoolVar(&Watch, "watch", false, "Watch input directory for changes")
	flag.BoolVar(&Preserve, "preserve", true, "Move input file as original into output directory")
	flag.BoolVar(&Upstart, "upstart", false, "Show an Upstart script for the specified config and exit")

	flag.Parse()

	if env := os.Getenv("TRANSLOADIT_KEY"); AuthKey == "" {
		AuthKey = env
	}

	if env := os.Getenv("TRANSLOADIT_SECRET"); AuthSecret == "" {
		AuthSecret = env
	}

}

func main() {

	if AuthKey == "" {
		log.Fatal("No TRANSLOADIT_KEY defined. Visit https://transloadit.com/accounts/credentials")
	}

	if AuthSecret == "" {
		log.Fatal("No TRANSLOADIT_SECRET defined. Visit https://transloadit.com/accounts/credentials")
	}

	if Upstart {
		upstartFile()
		return
	}

	if Output == "" {
		log.Fatal("No output directory defined")
	}

	if TemplateId == "" && TemplateFile == "" {
		log.Fatal("No template id or template file defined")
	}

	log.Printf("Converting all files in '%s' and putting the result into '%s'.", Input, Output)

	var steps map[string]map[string]interface{}
	if TemplateId != "" {
		log.Printf("Using template with id '%s'.", TemplateId)
	} else if TemplateFile != "" {
		steps = readJson(TemplateFile)
		log.Printf("Using template file '%s' (read %d steps).", TemplateFile, len(steps))
	}

	if Watch {
		log.Printf("Watching directory '%s' for changes...", Input)
	}

	config := transloadit.DefaultConfig
	config.AuthKey = AuthKey
	config.AuthSecret = AuthSecret

	client, err := transloadit.NewClient(&config)
	if err != nil {
		log.Fatal(err)
	}

	options := &transloadit.WatchOptions{
		Input:      Input,
		Output:     Output,
		Watch:      Watch,
		TemplateId: TemplateId,
		Preserve:   Preserve,
		Steps:      steps,
	}

	watcher := client.Watch(options)

	for {
		select {
		case err := <-watcher.Error:
			log.Printf("error: %s", err)
		case file := <-watcher.Change:
			log.Printf("Detected change for '%s'. Starting conversion...", file)
		case info := <-watcher.Done:
			log.Printf("Successfully converted '%s'.", info.Uploads[0].Name)
		}
	}

}

func readJson(file string) map[string]map[string]interface{} {

	content, err := ioutil.ReadFile(file)
	if err != nil {
		log.Fatalf("Error reading template file: %s", err)
	}

	steps := make(map[string]map[string]interface{})

	err = json.Unmarshal(content, &steps)
	if err != nil {
		log.Fatalf("Error parsing template file: %s", err)
	}

	return steps

}

type DaemonVars struct {
	Unixname string
	Username string
	Cmd      string
	Path     string
	Key      string
	Secret   string
}

func upstartFile() {
	var buf string

	buf = `description {{ .Unixname }}
author      "kvz.io"

start on (local-filesystems and net-device-up IFACE!=lo)
stop on shutdown
respawn
respawn limit 20 5

// Max open files are @ 1024 by default. Bit few.
limit nofile 32768 32768

script
  set -e
  mkfifo /tmp/{{ .Unixname }}-log-fifo
  ( logger -t {{ .Unixname }} </tmp/{{ .Unixname }}-log-fifo & )
  exec >/tmp/{{ .Unixname }}-log-fifo
  rm /tmp/{{ .Unixname }}-log-fifo
  exec bash -c "exec sudo -HEu{{ .Username }} env \
    PATH={{ .Path }} \
    TRANSLOADIT_KEY={{ .Key }} \
    TRANSLOADIT_SECRET={{ .Secret }} \
  {{ .Cmd }} 2>&1"
end script`

	// log.Printf("%s", buf)

	t := template.New("upstart")
	t, _ = t.Parse(buf)
	daemonVars := DaemonVars{
		Unixname: "transloadify",
		Username: os.Getenv("USER"),
		Cmd:      os.Args[0],
		Path:     os.Getenv("PATH"),
		Key:      os.Getenv("TRANSLOADIT_KEY"),
		Secret:   os.Getenv("TRANSLOADIT_SECRET"),
	}

	t.Execute(os.Stdout, daemonVars)
}
<commit_msg>Whitespace<commit_after>package main

import (
	"encoding/json"
	"flag"
	"github.com/transloadit/go-sdk"
	"io/ioutil"
	"log"
	"os"
	"text/template"
)

var AuthKey string
var AuthSecret string
var Input string
var Output string
var TemplateId string
var TemplateFile string
var Watch bool
var Preserve bool
var Upstart bool

func init() {
	flag.StringVar(&AuthKey, "key", "", "Auth key")
	flag.StringVar(&AuthSecret, "secret", "", "Auth secret")
	flag.StringVar(&Input, "input", ".", "Input directory")
	flag.StringVar(&Output, "output", "", "Output directory")
	flag.StringVar(&TemplateId, "template", "", "Template's id to create assemblies with")
	flag.StringVar(&TemplateFile, "template-file", "", "Path to local file containing template JSON")
	flag.BoolVar(&Watch, "watch", false, "Watch input directory for changes")
	flag.BoolVar(&Preserve, "preserve", true, "Move input file as original into output directory")
	flag.BoolVar(&Upstart, "upstart", false, "Show an Upstart script for the specified config and exit")
	flag.Parse()

	if env := os.Getenv("TRANSLOADIT_KEY"); AuthKey == "" {
		AuthKey = env
	}

	if env := os.Getenv("TRANSLOADIT_SECRET"); AuthSecret == "" {
		AuthSecret = env
	}
}

func main() {
	if AuthKey == "" {
		log.Fatal("No TRANSLOADIT_KEY defined. Visit https://transloadit.com/accounts/credentials")
	}

	if AuthSecret == "" {
		log.Fatal("No TRANSLOADIT_SECRET defined. Visit https://transloadit.com/accounts/credentials")
	}

	if Upstart {
		upstartFile()
		return
	}

	if Output == "" {
		log.Fatal("No output directory defined")
	}

	if TemplateId == "" && TemplateFile == "" {
		log.Fatal("No template id or template file defined")
	}

	log.Printf("Converting all files in '%s' and putting the result into '%s'.", Input, Output)

	var steps map[string]map[string]interface{}
	if TemplateId != "" {
		log.Printf("Using template with id '%s'.", TemplateId)
	} else if TemplateFile != "" {
		steps = readJson(TemplateFile)
		log.Printf("Using template file '%s' (read %d steps).", TemplateFile, len(steps))
	}

	if Watch {
		log.Printf("Watching directory '%s' for changes...", Input)
	}

	config := transloadit.DefaultConfig
	config.AuthKey = AuthKey
	config.AuthSecret = AuthSecret

	client, err := transloadit.NewClient(&config)
	if err != nil {
		log.Fatal(err)
	}

	options := &transloadit.WatchOptions{
		Input:      Input,
		Output:     Output,
		Watch:      Watch,
		TemplateId: TemplateId,
		Preserve:   Preserve,
		Steps:      steps,
	}
	watcher := client.Watch(options)

	for {
		select {
		case err := <-watcher.Error:
			log.Printf("error: %s", err)
		case file := <-watcher.Change:
			log.Printf("Detected change for '%s'. Starting conversion...", file)
		case info := <-watcher.Done:
			log.Printf("Successfully converted '%s'.", info.Uploads[0].Name)
		}
	}
}

func readJson(file string) map[string]map[string]interface{} {
	content, err := ioutil.ReadFile(file)
	if err != nil {
		log.Fatalf("Error reading template file: %s", err)
	}

	steps := make(map[string]map[string]interface{})

	err = json.Unmarshal(content, &steps)
	if err != nil {
		log.Fatalf("Error parsing template file: %s", err)
	}

	return steps
}

type DaemonVars struct {
	Unixname string
	Username string
	Cmd      string
	Path     string
	Key      string
	Secret   string
}

func upstartFile() {
	var buf string

	buf = `description {{ .Unixname }}
author      "kvz.io"

start on (local-filesystems and net-device-up IFACE!=lo)
stop on shutdown
respawn
respawn limit 20 5

// Max open files are @ 1024 by default. Bit few.
limit nofile 32768 32768

script
  set -e
  mkfifo /tmp/{{ .Unixname }}-log-fifo
  ( logger -t {{ .Unixname }} </tmp/{{ .Unixname }}-log-fifo & )
  exec >/tmp/{{ .Unixname }}-log-fifo
  rm /tmp/{{ .Unixname }}-log-fifo
  exec bash -c "exec sudo -HEu{{ .Username }} env \
    PATH={{ .Path }} \
    TRANSLOADIT_KEY={{ .Key }} \
    TRANSLOADIT_SECRET={{ .Secret }} \
  {{ .Cmd }} 2>&1"
end script`

	// log.Printf("%s", buf)

	t := template.New("upstart")
	t, _ = t.Parse(buf)
	daemonVars := DaemonVars{
		Unixname: "transloadify",
		Username: os.Getenv("USER"),
		Cmd:      os.Args[0],
		Path:     os.Getenv("PATH"),
		Key:      os.Getenv("TRANSLOADIT_KEY"),
		Secret:   os.Getenv("TRANSLOADIT_SECRET"),
	}

	t.Execute(os.Stdout, daemonVars)
}
<|endoftext|>


<commit_before>package quiclatest

import (
	"net"

	"github.com/ami-GS/gQUIC/latest/qtype"
)

type Client struct {
	*BasePacketHandler

	remoteAddr        net.Addr
	session           *Session
	versionOffer      qtype.Version
	versionNegotiated bool
}

func (c *Client) Ping() {
	c.session.ping()
}

func (s *Client) Send(data []byte) (int, error) {
	return s.session.Write(data)
}

func (s *Client) Close() {
	s.close(nil)
}

func (s *Client) close(f *ConnectionCloseFrame) {
	if f == nil {
		f = NewConnectionCloseFrame(0, qtype.NoError, "Close request from client")
	}
	s.session.Close(f)
}

func DialAddr(addr string) (*Client, error) {
	remoteAddr, err := net.ResolveUDPAddr("udp", addr)
	if err != nil {
		return nil, err
	}
	srcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
	udpConn, err := net.ListenUDP("udp", srcAddr)

	srcConnID, err := qtype.NewConnectionID(nil)
	if err != nil {
		return nil, err
	}
	// have same ID until getting Retry Packet
	destConnID := srcConnID

	cli := &Client{
		remoteAddr:        remoteAddr,
		session:           NewSession(&Connection{conn: udpConn, remoteAddr: remoteAddr}, srcConnID, destConnID, true),
		versionOffer:      qtype.VersionUnsupportedTest,
		versionNegotiated: false,
	}
	cli.session.packetHandler = cli
	go cli.run()
	cli.Connect()

	return cli, nil
}

func (c *Client) readTokenInfo() (*qtype.TokenInfo, bool) {
	return nil, false
}

func (c *Client) ReadUsableToken() []byte {
	// TODO: not fully implemented
	// 1. whether client has token? true -> 2.
	if tknInfo, exists := c.readTokenInfo(); exists {
		// 2. check local IP and network interface, is it different from that of used last time? true -> return last token.
		localAddr := c.session.conn.conn.LocalAddr().(*net.UDPAddr)
		if tknInfo.Addr != localAddr.String() {
			return nil
		}

		ifaces, err := net.Interfaces()
		if err != nil {
			panic(err)
		}
		for _, iface := range ifaces {
			addrs, err := iface.Addrs()
			if err != nil {
				panic(err)
			}

			for _, addr := range addrs {
				switch v := addr.(type) {
				case *net.IPNet:
					continue
				case *net.IPAddr:
					if localAddr.String() == v.IP.String() {
						if tknInfo.Iface == iface.Name {
							return tknInfo.Raw
						}
					}
				}
			}
		}

	}
	// For now, return nil
	return nil
}

func (c *Client) Connect() {
	// version negotiation
	// wait response

	token := c.ReadUsableToken()

	// first initial packet
	destID, _ := qtype.NewConnectionID(nil)
	c.session.sendPacketChan <- //NewCoalescingPacket([]Packet{
	NewInitialPacket(c.versionOffer, destID, destID, token, c.session.LastPacketNumber,
		[]Frame{NewCryptoFrame(0, []byte("first cryptographic handshake message (ClientHello)"))})
	//NewProtectedPacket0RTT(c.versionOffer, destID, destID, c.session.LastPacketNumber, []Frame{NewStreamFrame(0, 0, true, true, false, []byte("0-RTT[0]: STREAM[0, ...]"))}),
	//})
	c.session.DestConnID = destID
	c.session.SrcConnID = destID

	//
}

func (c *Client) run() {
	go c.session.Run()
	buffer := make([]byte, qtype.MTUIPv4)
	for {
		length, _, err := c.session.conn.Read(buffer)
		if err != nil {
			panic(err)
		}
		packets, _, err := ParsePackets(buffer[:length])
		if err != nil {
			panic(err)
		}

		for _, p := range packets {
			err = c.handlePacket(p)
			if err != nil {
				panic(err)
			}
		}

	}
}

func (c *Client) handlePacket(p Packet) error {
	if _, ok := p.(*VersionNegotiationPacket); !ok && c.versionNegotiated == false {
		c.versionNegotiated = true
		c.session.versionDecided = c.versionOffer
	}

	return c.session.HandlePacket(p)
}

func (c *Client) handleVersionNegotiationPacket(packet *VersionNegotiationPacket) error {
	// TODO: shoulsd be written in session?
	if c.versionNegotiated {
		// Once a client receives a packet from the server which is not a Version Negotiation
		// packet, it MUST discard other Version Negotiation packets on the same connection.
		return nil
	}
	if !c.session.SrcConnID.Equal(packet.DestConnID) || !c.session.DestConnID.Equal(packet.SrcConnID) {
		// If this check fails, the packet MUST be discarded.
		return nil
	}

	// TODO: priority queue?
	found := false
	versionTBD := qtype.Version(0)
	for _, version := range packet.SupportedVersions {
		if version == c.versionOffer {
			// MUST ignore a Version Negotiation packet that lists the client's chosen version.
			return nil
		}

		if !found {
			for _, supportedVersion := range qtype.SupportedVersions {
				if version == supportedVersion {
					found = true
					versionTBD = version
				}
			}
		}
	}
	c.versionOffer = versionTBD
	// WIP

	c.session.sendPacketChan <- NewInitialPacket(c.versionOffer, c.session.DestConnID, c.session.SrcConnID, nil,
		c.session.LastPacketNumber,
		[]Frame{NewCryptoFrame(0, []byte("second cryptographic handshake message for answering VersionNegotiation Packet"))})
	return nil
}

func (c *Client) handleRetryPacket(packet *RetryPacket) error {
	// send second initial packet

	// The client retains the state of its cryptographic handshake, but discards all transport state.
	c.session.DestConnID, _ = packet.GetHeader().GetConnectionIDPair()
	c.session.SrcConnID, _ = qtype.NewConnectionID(nil)
	c.session.RetryTokenReceived = packet.RetryToken

	// try again with new transport, but MUST remember the results of any version negotiation that occurred
	pn := packet.GetPacketNumber()
	c.session.sendPacketChan <- NewInitialPacket(c.session.versionDecided, c.session.DestConnID, c.session.SrcConnID,
		packet.RetryToken, pn.Increase(),
		[]Frame{NewCryptoFrame(qtype.QuicInt(len("first cryptographic handshake message (ClientHello)")), []byte("second cryptographic handshake message"))})
	return nil
}

func (c *Client) handleHandshakePacket(packet *HandshakePacket) error {
	return nil
}

func (c *Client) handleInitialPacket(packet *InitialPacket) error {
	pn := packet.GetPacketNumber()
	if packet.TokenLen != 0 {
		c.session.sendPacketChan <- NewProtectedPacket0RTT(c.session.versionDecided, c.session.DestConnID, c.session.SrcConnID, pn.Increase(), []Frame{NewConnectionCloseFrame(0, qtype.ProtocolViolation, "client receives initial packet with Non-zero token length")})
	}
	return nil
}
<commit_msg>add one handshake limitation spec<commit_after>package quiclatest

import (
	"bytes"
	"net"

	"github.com/ami-GS/gQUIC/latest/qtype"
)

type Client struct {
	*BasePacketHandler

	remoteAddr        net.Addr
	session           *Session
	versionOffer      qtype.Version
	versionNegotiated bool
}

func (c *Client) Ping() {
	c.session.ping()
}

func (s *Client) Send(data []byte) (int, error) {
	return s.session.Write(data)
}

func (s *Client) Close() {
	s.close(nil)
}

func (s *Client) close(f *ConnectionCloseFrame) {
	if f == nil {
		f = NewConnectionCloseFrame(0, qtype.NoError, "Close request from client")
	}
	s.session.Close(f)
}

func DialAddr(addr string) (*Client, error) {
	remoteAddr, err := net.ResolveUDPAddr("udp", addr)
	if err != nil {
		return nil, err
	}
	srcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
	udpConn, err := net.ListenUDP("udp", srcAddr)

	srcConnID, err := qtype.NewConnectionID(nil)
	if err != nil {
		return nil, err
	}
	// have same ID until getting Retry Packet
	destConnID := srcConnID

	cli := &Client{
		remoteAddr:        remoteAddr,
		session:           NewSession(&Connection{conn: udpConn, remoteAddr: remoteAddr}, srcConnID, destConnID, true),
		versionOffer:      qtype.VersionUnsupportedTest,
		versionNegotiated: false,
	}
	cli.session.packetHandler = cli
	go cli.run()
	cli.Connect()

	return cli, nil
}

func (c *Client) readTokenInfo() (*qtype.TokenInfo, bool) {
	return nil, false
}

func (c *Client) ReadUsableToken() []byte {
	// TODO: not fully implemented
	// 1. whether client has token? true -> 2.
	if tknInfo, exists := c.readTokenInfo(); exists {
		// 2. check local IP and network interface, is it different from that of used last time? true -> return last token.
		localAddr := c.session.conn.conn.LocalAddr().(*net.UDPAddr)
		if tknInfo.Addr != localAddr.String() {
			return nil
		}

		ifaces, err := net.Interfaces()
		if err != nil {
			panic(err)
		}
		for _, iface := range ifaces {
			addrs, err := iface.Addrs()
			if err != nil {
				panic(err)
			}

			for _, addr := range addrs {
				switch v := addr.(type) {
				case *net.IPNet:
					continue
				case *net.IPAddr:
					if localAddr.String() == v.IP.String() {
						if tknInfo.Iface == iface.Name {
							return tknInfo.Raw
						}
					}
				}
			}
		}

	}
	// For now, return nil
	return nil
}

func (c *Client) Connect() {
	// version negotiation
	// wait response

	token := c.ReadUsableToken()

	// first initial packet
	destID, _ := qtype.NewConnectionID(nil)
	c.session.sendPacketChan <- //NewCoalescingPacket([]Packet{
	NewInitialPacket(c.versionOffer, destID, destID, token, c.session.LastPacketNumber,
		[]Frame{NewCryptoFrame(0, []byte("first cryptographic handshake message (ClientHello)"))})
	//NewProtectedPacket0RTT(c.versionOffer, destID, destID, c.session.LastPacketNumber, []Frame{NewStreamFrame(0, 0, true, true, false, []byte("0-RTT[0]: STREAM[0, ...]"))}),
	//})
	c.session.DestConnID = destID
	c.session.SrcConnID = destID

	//
}

func (c *Client) run() {
	go c.session.Run()
	buffer := make([]byte, qtype.MTUIPv4)
	for {
		length, _, err := c.session.conn.Read(buffer)
		if err != nil {
			panic(err)
		}
		packets, _, err := ParsePackets(buffer[:length])
		if err != nil {
			panic(err)
		}

		for _, p := range packets {
			err = c.handlePacket(p)
			if err != nil {
				panic(err)
			}
		}

	}
}

func (c *Client) handlePacket(p Packet) error {
	if _, ok := p.(*VersionNegotiationPacket); !ok && c.versionNegotiated == false {
		c.versionNegotiated = true
		c.session.versionDecided = c.versionOffer
	}

	return c.session.HandlePacket(p)
}

func (c *Client) handleVersionNegotiationPacket(packet *VersionNegotiationPacket) error {
	// TODO: shoulsd be written in session?
	if c.versionNegotiated {
		// Once a client receives a packet from the server which is not a Version Negotiation
		// packet, it MUST discard other Version Negotiation packets on the same connection.
		return nil
	}
	if !c.session.SrcConnID.Equal(packet.DestConnID) || !c.session.DestConnID.Equal(packet.SrcConnID) {
		// If this check fails, the packet MUST be discarded.
		return nil
	}

	// TODO: priority queue?
	found := false
	versionTBD := qtype.Version(0)
	for _, version := range packet.SupportedVersions {
		if version == c.versionOffer {
			// MUST ignore a Version Negotiation packet that lists the client's chosen version.
			return nil
		}

		if !found {
			for _, supportedVersion := range qtype.SupportedVersions {
				if version == supportedVersion {
					found = true
					versionTBD = version
				}
			}
		}
	}
	c.versionOffer = versionTBD
	// WIP

	c.session.sendPacketChan <- NewInitialPacket(c.versionOffer, c.session.DestConnID, c.session.SrcConnID, nil,
		c.session.LastPacketNumber,
		[]Frame{NewCryptoFrame(0, []byte("second cryptographic handshake message for answering VersionNegotiation Packet"))})
	return nil
}

func (c *Client) handleRetryPacket(packet *RetryPacket) error {
	// send second initial packet

	// The client retains the state of its cryptographic handshake, but discards all transport state.
	//c.session.DestConnID, _ = packet.GetHeader().GetConnectionIDPair()
	_, destConnID := packet.GetHeader().GetConnectionIDPair()
	if !bytes.Equal(destConnID, c.session.DestConnID) {
		/*
		   Clients MUST discard Retry packets that contain an Original
		   Destination Connection ID field that does not match the Destination
		   Connection ID from its Initial packet.  This prevents an off-path
		   attacker from injecting a Retry packet.
		*/
		// any error?
		panic("destConnID mismatch")
		return nil
	}
	c.session.SrcConnID, _ = qtype.NewConnectionID(nil)
	c.session.RetryTokenReceived = packet.RetryToken

	// try again with new transport, but MUST remember the results of any version negotiation that occurred
	pn := packet.GetPacketNumber()
	c.session.sendPacketChan <- NewInitialPacket(c.session.versionDecided, c.session.DestConnID, c.session.SrcConnID,
		packet.RetryToken, pn.Increase(),
		[]Frame{NewCryptoFrame(qtype.QuicInt(len("first cryptographic handshake message (ClientHello)")), []byte("second cryptographic handshake message"))})
	return nil
}

func (c *Client) handleHandshakePacket(packet *HandshakePacket) error {
	return nil
}

func (c *Client) handleInitialPacket(packet *InitialPacket) error {
	pn := packet.GetPacketNumber()
	if packet.TokenLen != 0 {
		c.session.sendPacketChan <- NewProtectedPacket0RTT(c.session.versionDecided, c.session.DestConnID, c.session.SrcConnID, pn.Increase(), []Frame{NewConnectionCloseFrame(0, qtype.ProtocolViolation, "client receives initial packet with Non-zero token length")})
	}
	return nil
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2017 Mainflux
//
// SPDX-License-Identifier: Apache-2.0
//

package distro

// TODO:
// - Filtering by id and value
// - Receive events from 0mq until a new message broker/rpc is chosen
// - Implement json/xml/.... serializers
// - Senders should not connect at creation time, but when first event comes.
//   - Reconnect after disconnect
//   - Event buffer management per sender(do not block distro.Loop on full
//   registration channel)

import (
	"time"

	"github.com/drasko/edgex-export"
	"github.com/drasko/edgex-export/mongo"
	"go.uber.org/zap"
)

// To be removed when any other formater is implemented
type dummyFormat struct {
}

func (dummy dummyFormat) Format( /*event*/ ) []byte {
	return []byte("dummy")
}

var dummy dummyFormat

func (reg *RegistrationInfo) update(newReg export.Registration) bool {
	reg.registration = newReg

	reg.format = nil
	switch newReg.Format {
	case export.FormatJSON:
		// TODO reg.format = distro.NewJsonFormat()
		reg.format = dummy
	case export.FormatXML:
		// TODO reg.format = distro.NewXmlFormat()
		reg.format = dummy
	case export.FormatSerialized:
		// TODO reg.format = distro.NewSerializedFormat()
	case export.FormatIoTCoreJSON:
		// TODO reg.format = distro.NewIotCoreFormat()
	case export.FormatAzureJSON:
		// TODO reg.format = distro.NewAzureFormat()
	case export.FormatCSV:
		// TODO reg.format = distro.NewCsvFormat()
	default:
		logger.Info("Format not supported: ", zap.String("format", newReg.Format))
	}

	reg.compression = nil
	switch newReg.Compression {
	case export.CompNone:
		reg.compression = nil
	case export.CompGzip:
		reg.compression = gzipTransformer{}
	case export.CompZip:
		reg.compression = zlibTransformer{}
	default:
		logger.Info("Compression not supported: ", zap.String("compression", newReg.Compression))
	}

	reg.sender = nil
	switch newReg.Destination {
	case export.DestMQTT:
		reg.sender = NewMqttSender(newReg.Addressable)
	case export.DestZMQ:
		logger.Info("Destination ZMQ is not supported")
	case export.DestIotCoreMQTT:
		// TODO reg.sender = distro.NewIotCoreSender("TODO URL")
	case export.DestAzureMQTT:
		// TODO reg.sender = distro.NewAzureSender("TODO URL")
	case export.DestRest:
		reg.sender = NewHttpSender(newReg.Addressable)
	default:
		logger.Info("Destination not supported: ", zap.String("destination", newReg.Destination))
	}
	if reg.format == nil || reg.sender == nil {
		logger.Error("Registration not supported")
		return false
	}

	reg.chRegistration = make(chan *RegistrationInfo)
	reg.chEvent = make(chan bool)

	return true
}

func (reg RegistrationInfo) processEvent( /*event*/ ) {
	// Valid Event Filter, needed?

	// TODO Device filtering

	// TODO Value filtering
	formated := reg.format.Format( /* event*/ )
	compressed := formated
	if reg.compression != nil {
		compressed = reg.compression.Transform(formated)
	}

	encrypted := compressed
	if reg.encrypt != nil {
		encrypted = reg.encrypt.Transform(compressed)
	}

	reg.sender.Send(encrypted)
}

func registrationLoop(reg RegistrationInfo) {
	logger.Info("registration loop started")
	for {
		select {
		case /*event :=*/ <-reg.chEvent:
			reg.processEvent( /*event*/ )

		case newResgistration := <-reg.chRegistration:
			if newResgistration == nil {
				logger.Info("Terminate registration goroutine")
			} else {
				// TODO implement updating the registration info.
				logger.Info("Registration updated")
			}
		}
	}
}

func Loop(repo *mongo.MongoRepository, errChan chan error) {

	var registrations []RegistrationInfo

	sourceReg := getRegistrations(repo)

	for i := range sourceReg {
		var reg RegistrationInfo
		if reg.update(sourceReg[i]) {
			registrations = append(registrations, reg)
			go registrationLoop(reg)
		}
	}

	logger.Info("Starting resgistration loop")
	for {
		select {
		case e := <-errChan:
			// kill all registration goroutines
			for r := range registrations {
				registrations[r].chRegistration <- nil
			}
			logger.Info("exit msg", zap.Error(e))
			return

		case <-time.After(time.Millisecond / 10):
			// Simulate receiving 10k events/seg
			for r := range registrations {
				// TODO only sent event if it is not blocking
				registrations[r].chEvent <- true
			}
		}
	}
}
<commit_msg>Fixed typos 'resg*'<commit_after>//
// Copyright (c) 2017 Mainflux
//
// SPDX-License-Identifier: Apache-2.0
//

package distro

// TODO:
// - Filtering by id and value
// - Receive events from 0mq until a new message broker/rpc is chosen
// - Implement json/xml/.... serializers
// - Senders should not connect at creation time, but when first event comes.
//   - Reconnect after disconnect
//   - Event buffer management per sender(do not block distro.Loop on full
//   registration channel)

import (
	"time"

	"github.com/drasko/edgex-export"
	"github.com/drasko/edgex-export/mongo"
	"go.uber.org/zap"
)

// To be removed when any other formater is implemented
type dummyFormat struct {
}

func (dummy dummyFormat) Format( /*event*/ ) []byte {
	return []byte("dummy")
}

var dummy dummyFormat

func (reg *RegistrationInfo) update(newReg export.Registration) bool {
	reg.registration = newReg

	reg.format = nil
	switch newReg.Format {
	case export.FormatJSON:
		// TODO reg.format = distro.NewJsonFormat()
		reg.format = dummy
	case export.FormatXML:
		// TODO reg.format = distro.NewXmlFormat()
		reg.format = dummy
	case export.FormatSerialized:
		// TODO reg.format = distro.NewSerializedFormat()
	case export.FormatIoTCoreJSON:
		// TODO reg.format = distro.NewIotCoreFormat()
	case export.FormatAzureJSON:
		// TODO reg.format = distro.NewAzureFormat()
	case export.FormatCSV:
		// TODO reg.format = distro.NewCsvFormat()
	default:
		logger.Info("Format not supported: ", zap.String("format", newReg.Format))
	}

	reg.compression = nil
	switch newReg.Compression {
	case export.CompNone:
		reg.compression = nil
	case export.CompGzip:
		reg.compression = gzipTransformer{}
	case export.CompZip:
		reg.compression = zlibTransformer{}
	default:
		logger.Info("Compression not supported: ", zap.String("compression", newReg.Compression))
	}

	reg.sender = nil
	switch newReg.Destination {
	case export.DestMQTT:
		reg.sender = NewMqttSender(newReg.Addressable)
	case export.DestZMQ:
		logger.Info("Destination ZMQ is not supported")
	case export.DestIotCoreMQTT:
		// TODO reg.sender = distro.NewIotCoreSender("TODO URL")
	case export.DestAzureMQTT:
		// TODO reg.sender = distro.NewAzureSender("TODO URL")
	case export.DestRest:
		reg.sender = NewHttpSender(newReg.Addressable)
	default:
		logger.Info("Destination not supported: ", zap.String("destination", newReg.Destination))
	}
	if reg.format == nil || reg.sender == nil {
		logger.Error("Registration not supported")
		return false
	}

	reg.chRegistration = make(chan *RegistrationInfo)
	reg.chEvent = make(chan bool)

	return true
}

func (reg RegistrationInfo) processEvent( /*event*/ ) {
	// Valid Event Filter, needed?

	// TODO Device filtering

	// TODO Value filtering
	formated := reg.format.Format( /* event*/ )
	compressed := formated
	if reg.compression != nil {
		compressed = reg.compression.Transform(formated)
	}

	encrypted := compressed
	if reg.encrypt != nil {
		encrypted = reg.encrypt.Transform(compressed)
	}

	reg.sender.Send(encrypted)
}

func registrationLoop(reg RegistrationInfo) {
	logger.Info("registration loop started")
	for {
		select {
		case /*event :=*/ <-reg.chEvent:
			reg.processEvent( /*event*/ )

		case newReg := <-reg.chRegistration:
			if newReg == nil {
				logger.Info("Terminate registration goroutine")
			} else {
				// TODO implement updating the registration info.
				logger.Info("Registration updated")
			}
		}
	}
}

func Loop(repo *mongo.MongoRepository, errChan chan error) {

	var registrations []RegistrationInfo

	sourceReg := getRegistrations(repo)

	for i := range sourceReg {
		var reg RegistrationInfo
		if reg.update(sourceReg[i]) {
			registrations = append(registrations, reg)
			go registrationLoop(reg)
		}
	}

	logger.Info("Starting registration loop")
	for {
		select {
		case e := <-errChan:
			// kill all registration goroutines
			for r := range registrations {
				registrations[r].chRegistration <- nil
			}
			logger.Info("exit msg", zap.Error(e))
			return

		case <-time.After(time.Millisecond / 10):
			// Simulate receiving 10k events/seg
			for r := range registrations {
				// TODO only sent event if it is not blocking
				registrations[r].chEvent <- true
			}
		}
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, Peter Mrekaj. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE.txt file.

package graphs

// isFeasible returns true if c is inside the maze and is white.
func isFeasible(maze [][]bool, c Coordinate) bool {
	return c.x >= 0 && c.x < len(maze) && c.y >= 0 && c.y < len(maze[c.x]) && maze[c.x][c.y] == white
}

// pathExists returns true if path from curr to end exists in maze.
// Function is recursive implementation of DFS.
func pathExists(maze [][]bool, curr, end Coordinate, path *[]Coordinate) bool {
	if curr == end { // Base case.
		return true
	}

	for _, shift := range []Coordinate{right, left, down, up} {
		next := Coordinate{curr.x + shift.x, curr.y + shift.y}
		if isFeasible(maze, next) { // Check if we can move this way.
			*path = append(*path, next)
			maze[next.x][next.y] = black // Mark as visited.
			if pathExists(maze, next, end, path) {
				return true
			}
			*path = (*path)[:len(*path)-1] // e wasn't found, take step back and try another one.
		}
	}
	return false
}

// SearchMaze returns true if a path exists from start to end in the maze.
// The time complexity is O(v+e) where v is the number of vertices and e is the
// number of edges in maze. Vertex is represented by boolean value true and edge
// connects two vertices. O(v) additional space is needed.
func SearchMaze(maze [][]bool, start, end Coordinate) (path []Coordinate) {
	if !isFeasible(maze, start) {
		return path
	}
	path = append(path, start)
	maze[start.x][start.y] = black // Mark as visited.
	if !pathExists(maze, start, end, &path) {
		return nil
	}
	return path
}
<commit_msg>Refactor recursion helper function to use function literal<commit_after>// Copyright (c) 2015, Peter Mrekaj. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE.txt file.

package graphs

// isFeasible returns true if c is inside the maze and is white.
func isFeasible(maze [][]bool, c Coordinate) bool {
	return c.x >= 0 && c.x < len(maze) && c.y >= 0 && c.y < len(maze[c.x]) && maze[c.x][c.y] == white
}

// SearchMaze returns true if a path exists from start to end in the maze.
// The time complexity is O(v+e) where v is the number of vertices and e is the
// number of edges in maze. Vertex is represented by boolean value true and edge
// connects two vertices. O(v) additional space is needed.
func SearchMaze(maze [][]bool, start, end Coordinate) (path []Coordinate) {
	if !isFeasible(maze, start) {
		return path
	}
	path = append(path, start)
	maze[start.x][start.y] = black // Mark as visited.

	// pathExists returns true if path from curr to end exists in maze.
	// Function is recursive implementation of DFS.
	var pathExists func(maze [][]bool, curr, end Coordinate) bool
	pathExists = func(maze [][]bool, curr, end Coordinate) bool {
		if curr == end { // Base case.
			return true
		}

		for _, shift := range []Coordinate{right, left, down, up} {
			next := Coordinate{curr.x + shift.x, curr.y + shift.y}
			if isFeasible(maze, next) { // Check if we can move this way.
				path = append(path, next)
				maze[next.x][next.y] = black // Mark as visited.
				if pathExists(maze, next, end) {
					return true
				}
				path = path[:len(path)-1] // End wasn't found, take step back and try another one.
			}
		}
		return false
	}

	if !pathExists(maze, start, end) {
		return nil
	}
	return path
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"time"

	"code.google.com/p/go-imap/go1/imap"
	"code.google.com/p/gopass"
)

var (
	login   = flag.String("login", "", "Your login")
	mailbox = flag.String("mailbox", "[Gmail]/All Mail", "The mailbox to watch")
	server  = flag.String("server", "imap.gmail.com", "Your IMAP server with TLS")
)

func main() {
	flag.Parse()
	if *login == "" {
		fmt.Println("I need at least your login!\n")
		flag.Usage()
		os.Exit(1)
	}

	pass, err := gopass.GetPass("Password: ")
	if err != nil {
		log.Fatal(err)
	}

	quit := make(chan os.Signal)
	signal.Notify(quit, os.Interrupt, os.Kill)
	go func() {
		<-quit
		os.Exit(0)
	}()

	connect := func(server string) (c *imap.Client, err error) {
		c, err = imap.DialTLS(server, &tls.Config{})
		if err != nil {
			return
		}

		_, err = c.Auth(imap.PlainAuth(*login, pass, ""))
		if err != nil {
			return
		}

		log.Println("Successfully authed")

		cmd, err := c.Select(*mailbox, true)
		if err != nil {
			log.Println("Error selecting mailbox: ", err)
			return
		}
		_, err = cmd.Result(imap.OK)
		if err != nil {
			return
		}

		log.Println("Successfully selected ", *mailbox)

		_, err = c.Idle()
		if err != nil {
			return
		}

		log.Println("Starting idle...")
		c.Data = nil

		return
	}

loop:
	for {
		c, err := connect(*server)
		if err != nil {
			continue
		}

		wait := true
		for wait {
			err = c.Recv(15 * time.Minute)
			switch err {
			case nil:
				fallthrough
			case io.EOF:
				// We received content from server -- sync mails
				wait = false
			case imap.ErrTimeout:
				// after the timeout, wakeup the connection
				if _, err := c.IdleTerm(); err != nil {
					log.Println("Error finishing idle:: ", err)
					continue loop
				}
				if _, err := imap.Wait(c.Noop()); err != nil {
					log.Println("Error nooping: ", err)
					continue loop
				}
				log.Println("Keeping it alive !")
				if _, err := c.Idle(); err != nil {
					log.Println("Error re-idling: ", err)
					continue loop
				}
			default:
				log.Println("Error while receiving content: ", err)
				continue loop
			}
		}

		for _, rsp := range c.Data {
			if rsp.Label == "EXISTS" {
				log.Println("New message, running sync...")
				cmd := exec.Command("offlineimap", "-u", "Quiet")
				cmd.Stdout = os.Stderr
				cmd.Stderr = os.Stderr
				err := cmd.Run()
				if err != nil {
					log.Printf("Error running sync: %s\n", err)
				}
				log.Println("Ran sync")
			}
		}

		c.Data = nil
	}
}
<commit_msg>Parse login and password from OfflineIMAP's ini file<commit_after>package main

import (
	"crypto/tls"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"strings"
	"time"

	"github.com/rakoo/go-ini"

	"code.google.com/p/go-imap/go1/imap"
)

var (
	mailbox = flag.String("mailbox", "[Gmail]/All Mail", "The mailbox to watch")
)

func main() {
	flag.Parse()
	email, password := getCredentials()

	quit := make(chan os.Signal)
	signal.Notify(quit, os.Interrupt, os.Kill)
	go func() {
		<-quit
		os.Exit(0)
	}()

	connect := func(server string) (c *imap.Client, err error) {
		c, err = imap.DialTLS(server, &tls.Config{})
		if err != nil {
			return
		}

		_, err = c.Auth(imap.PlainAuth(email, password, ""))
		if err != nil {
			return
		}

		log.Println("Successfully authed")

		cmd, err := c.Select(*mailbox, true)
		if err != nil {
			log.Println("Error selecting mailbox: ", err)
			return
		}
		_, err = cmd.Result(imap.OK)
		if err != nil {
			return
		}

		log.Println("Successfully selected ", *mailbox)

		_, err = c.Idle()
		if err != nil {
			return
		}

		log.Println("Starting idle...")
		c.Data = nil

		return
	}

loop:
	for {
		c, err := connect("imap.gmail.com")
		if err != nil {
			continue
		}

		wait := true
		for wait {
			err = c.Recv(15 * time.Minute)
			switch err {
			case nil:
				fallthrough
			case io.EOF:
				// We received content from server -- sync mails
				wait = false
			case imap.ErrTimeout:
				// after the timeout, wakeup the connection
				if _, err := c.IdleTerm(); err != nil {
					log.Println("Error finishing idle:: ", err)
					continue loop
				}
				if _, err := imap.Wait(c.Noop()); err != nil {
					log.Println("Error nooping: ", err)
					continue loop
				}
				log.Println("Keeping it alive !")
				if _, err := c.Idle(); err != nil {
					log.Println("Error re-idling: ", err)
					continue loop
				}
			default:
				log.Println("Error while receiving content: ", err)
				continue loop
			}
		}

		for _, rsp := range c.Data {
			if rsp.Label == "EXISTS" {
				log.Println("New message, running sync...")
				cmd := exec.Command("offlineimap", "-u", "Quiet")
				cmd.Stdout = os.Stderr
				cmd.Stderr = os.Stderr
				err := cmd.Run()
				if err != nil {
					log.Printf("Error running sync: %s\n", err)
				}
				log.Println("Ran sync")
			}
		}

		c.Data = nil
	}
}

func getCredentials() (email, password string) {
	cfg, err := ini.LoadFile(filepath.Join(os.Getenv("HOME"),
		".offlineimaprc"))
	if err != nil {
		log.Fatal(err)
	}

	accounts, ok := cfg.Get("general", "accounts")
	if !ok {
		log.Fatal("No general/accounts string")
	}

	// Only take first one
	account := strings.Split(accounts, ",")[0]
	remoterepo, ok := cfg.Get("Account "+account, "remoterepository")
	if !ok {
		log.Fatal(fmt.Sprintf("No section 'Account %s'/remoterepository",
			account))
	}

	typ, ok := cfg.Get("Repository "+remoterepo, "type")
	if !ok {
		log.Fatal("No type in repo")
	}
	if typ != "Gmail" {
		log.Fatal("I can only manage Gmail repos; curren type is ", typ)
	}
	user, okuser := cfg.Get("Repository "+remoterepo, "remoteuser")
	password, okpass := cfg.Get("Repository "+remoterepo, "remotepass")
	if !okuser || !okpass {
		log.Fatal("Invalid config")
	}

	return user + "@gmail.com", password
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package gcsproxy_test

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"testing"

	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/gcs/mock_gcs"
	"github.com/jacobsa/gcsfuse/gcsproxy"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"golang.org/x/net/context"
	"google.golang.org/cloud/storage"
)

func TestOgletest(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

// An oglemock.Matcher that accepts a predicate function and a description,
// making it easy to make anonymous matcher types.
type predicateMatcher struct {
	Desc      string
	Predicate func(interface{}) error
}

var _ Matcher = &predicateMatcher{}

func (m *predicateMatcher) Matches(candidate interface{}) error {
	return m.Predicate(candidate)
}

func (m *predicateMatcher) Description() string {
	return m.Desc
}

func nameIs(name string) Matcher {
	return &predicateMatcher{
		Desc: fmt.Sprintf("Name is: %s", name),
		Predicate: func(candidate interface{}) error {
			req := candidate.(*gcs.CreateObjectRequest)
			if req.Attrs.Name != name {
				return errors.New("")
			}

			return nil
		},
	}
}

func contentsAre(s string) Matcher {
	return &predicateMatcher{
		Desc: fmt.Sprintf("Object contents are: %s", s),
		Predicate: func(candidate interface{}) error {
			// Snarf the contents.
			req := candidate.(*gcs.CreateObjectRequest)
			contents, err := ioutil.ReadAll(req.Contents)
			if err != nil {
				panic(err)
			}

			// Compare
			if string(contents) != s {
				return errors.New("")
			}

			return nil
		},
	}
}

////////////////////////////////////////////////////////////////////////
// Invariant-checking object proxy
////////////////////////////////////////////////////////////////////////

// A wrapper around ObjectProxy that calls CheckInvariants whenever invariants
// should hold. For catching logic errors early in the test.
type checkingObjectProxy struct {
	wrapped *gcsproxy.ObjectProxy
}

func (op *checkingObjectProxy) Name() string {
	op.wrapped.CheckInvariants()
	defer op.wrapped.CheckInvariants()
	return op.wrapped.Name()
}

func (op *checkingObjectProxy) Stat() (uint64, bool, error) {
	op.wrapped.CheckInvariants()
	defer op.wrapped.CheckInvariants()
	return op.wrapped.Stat(context.Background())
}

func (op *checkingObjectProxy) ReadAt(b []byte, o int64) (int, error) {
	op.wrapped.CheckInvariants()
	defer op.wrapped.CheckInvariants()
	return op.wrapped.ReadAt(context.Background(), b, o)
}

func (op *checkingObjectProxy) WriteAt(b []byte, o int64) (int, error) {
	op.wrapped.CheckInvariants()
	defer op.wrapped.CheckInvariants()
	return op.wrapped.WriteAt(context.Background(), b, o)
}

func (op *checkingObjectProxy) Truncate(n uint64) error {
	op.wrapped.CheckInvariants()
	defer op.wrapped.CheckInvariants()
	return op.wrapped.Truncate(context.Background(), n)
}

func (op *checkingObjectProxy) Sync() (uint64, error) {
	op.wrapped.CheckInvariants()
	defer op.wrapped.CheckInvariants()
	return op.wrapped.Sync(context.Background())
}

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type ObjectProxyTest struct {
	objectName string
	bucket     mock_gcs.MockBucket
	op         checkingObjectProxy
}

func (t *ObjectProxyTest) setUp(ti *TestInfo, srcGeneration uint64) {
	t.objectName = "some/object"
	t.bucket = mock_gcs.NewMockBucket(ti.MockController, "bucket")

	var err error
	t.op.wrapped, err = gcsproxy.NewObjectProxy(
		context.Background(),
		t.bucket,
		t.objectName,
		srcGeneration)

	if err != nil {
		panic(err)
	}
}

////////////////////////////////////////////////////////////////////////
// No source object
////////////////////////////////////////////////////////////////////////

// A test whose initial conditions are a fresh object proxy without a source
// object set.
type NoSourceObjectTest struct {
	ObjectProxyTest
}

var _ SetUpInterface = &NoSourceObjectTest{}

func init() { RegisterTestSuite(&NoSourceObjectTest{}) }

func (t *NoSourceObjectTest) SetUp(ti *TestInfo) {
	t.ObjectProxyTest.setUp(ti, 0)
}

func (t *NoSourceObjectTest) Name() {
	ExpectEq(t.objectName, t.op.Name())
}

func (t *NoSourceObjectTest) Read_InitialState() {
	buf := make([]byte, 1024)
	n, err := t.op.ReadAt(buf, 0)

	ExpectEq(io.EOF, err)
	ExpectEq(0, n)
}

func (t *NoSourceObjectTest) WriteToEndOfObjectThenRead() {
	var buf []byte
	var n int
	var err error

	// Extend the object by writing twice.
	n, err = t.op.WriteAt([]byte("taco"), 0)
	AssertEq(nil, err)
	AssertEq(len("taco"), n)

	n, err = t.op.WriteAt([]byte("burrito"), int64(len("taco")))
	AssertEq(nil, err)
	AssertEq(len("burrito"), n)

	// Read the whole thing.
	buf = make([]byte, 1024)
	n, err = t.op.ReadAt(buf, 0)

	AssertEq(io.EOF, err)
	ExpectEq(len("tacoburrito"), n)
	ExpectEq("tacoburrito", string(buf[:n]))

	// Read a range in the middle.
	buf = make([]byte, 4)
	n, err = t.op.ReadAt(buf, 3)

	AssertEq(nil, err)
	ExpectEq(4, n)
	ExpectEq("obur", string(buf[:n]))
}

func (t *NoSourceObjectTest) WritePastEndOfObjectThenRead() {
	var n int
	var err error
	var buf []byte

	// Extend the object by writing past its end.
	n, err = t.op.WriteAt([]byte("taco"), 2)
	AssertEq(nil, err)
	AssertEq(len("taco"), n)

	// Read the whole thing.
	buf = make([]byte, 1024)
	n, err = t.op.ReadAt(buf, 0)

	AssertEq(io.EOF, err)
	ExpectEq(2+len("taco"), n)
	ExpectEq("\x00\x00taco", string(buf[:n]))

	// Read a range in the middle.
	buf = make([]byte, 4)
	n, err = t.op.ReadAt(buf, 1)

	AssertEq(nil, err)
	ExpectEq(4, n)
	ExpectEq("\x00tac", string(buf[:n]))
}

func (t *NoSourceObjectTest) WriteWithinObjectThenRead() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) GrowByTruncating() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Sync_NoInteractions() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Sync_ReadCallsOnly() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Sync_AfterWriting() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Sync_AfterTruncating() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Sync_CreateObjectFails() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Sync_CreateObjectSaysPreconditionFailed() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Sync_Successful() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Stat_CallsBucket() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Stat_BucketFails() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Stat_InitialState() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Stat_AfterShortening() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Stat_AfterGrowing() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Stat_AfterReading() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Stat_AfterWriting() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Stat_Clobbered() {
	AssertTrue(false, "TODO")
}

////////////////////////////////////////////////////////////////////////
// Source object present
////////////////////////////////////////////////////////////////////////

// A test whose initial conditions are an object proxy branching from a source
// object in the bucket.
type SourceObjectPresentTest struct {
	ObjectProxyTest
	sourceObject *storage.Object
}

var _ SetUpInterface = &SourceObjectPresentTest{}

func init() { RegisterTestSuite(&SourceObjectPresentTest{}) }

func (t *SourceObjectPresentTest) SetUp(ti *TestInfo) {
	t.ObjectProxyTest.setUp(ti, 123)
}

func (t *SourceObjectPresentTest) Read_CallsNewReader() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Read_NewReaderFails() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Read_NewReaderSucceeds() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Write_CallsNewReader() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Write_NewReaderFails() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Write_NewReaderSucceeds() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Truncate_CallsNewReader() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Truncate_NewReaderFails() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Truncate_NewReaderSucceeds() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Sync_NoInteractions() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Sync_CallsCreateObject() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Stat_CallsBucket() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Stat_BucketFails() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Stat_BucketSaysNotFound() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Stat_InitialState() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Stat_AfterShortening() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Stat_AfterGrowing() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Stat_AfterReading() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Stat_AfterWriting() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Stat_Clobbered() {
	AssertTrue(false, "TODO")
}
<commit_msg>NoSourceObjectTest.WriteWithinObjectThenRead<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package gcsproxy_test

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"testing"

	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/gcs/mock_gcs"
	"github.com/jacobsa/gcsfuse/gcsproxy"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"golang.org/x/net/context"
	"google.golang.org/cloud/storage"
)

func TestOgletest(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

// An oglemock.Matcher that accepts a predicate function and a description,
// making it easy to make anonymous matcher types.
type predicateMatcher struct {
	Desc      string
	Predicate func(interface{}) error
}

var _ Matcher = &predicateMatcher{}

func (m *predicateMatcher) Matches(candidate interface{}) error {
	return m.Predicate(candidate)
}

func (m *predicateMatcher) Description() string {
	return m.Desc
}

func nameIs(name string) Matcher {
	return &predicateMatcher{
		Desc: fmt.Sprintf("Name is: %s", name),
		Predicate: func(candidate interface{}) error {
			req := candidate.(*gcs.CreateObjectRequest)
			if req.Attrs.Name != name {
				return errors.New("")
			}

			return nil
		},
	}
}

func contentsAre(s string) Matcher {
	return &predicateMatcher{
		Desc: fmt.Sprintf("Object contents are: %s", s),
		Predicate: func(candidate interface{}) error {
			// Snarf the contents.
			req := candidate.(*gcs.CreateObjectRequest)
			contents, err := ioutil.ReadAll(req.Contents)
			if err != nil {
				panic(err)
			}

			// Compare
			if string(contents) != s {
				return errors.New("")
			}

			return nil
		},
	}
}

////////////////////////////////////////////////////////////////////////
// Invariant-checking object proxy
////////////////////////////////////////////////////////////////////////

// A wrapper around ObjectProxy that calls CheckInvariants whenever invariants
// should hold. For catching logic errors early in the test.
type checkingObjectProxy struct {
	wrapped *gcsproxy.ObjectProxy
}

func (op *checkingObjectProxy) Name() string {
	op.wrapped.CheckInvariants()
	defer op.wrapped.CheckInvariants()
	return op.wrapped.Name()
}

func (op *checkingObjectProxy) Stat() (uint64, bool, error) {
	op.wrapped.CheckInvariants()
	defer op.wrapped.CheckInvariants()
	return op.wrapped.Stat(context.Background())
}

func (op *checkingObjectProxy) ReadAt(b []byte, o int64) (int, error) {
	op.wrapped.CheckInvariants()
	defer op.wrapped.CheckInvariants()
	return op.wrapped.ReadAt(context.Background(), b, o)
}

func (op *checkingObjectProxy) WriteAt(b []byte, o int64) (int, error) {
	op.wrapped.CheckInvariants()
	defer op.wrapped.CheckInvariants()
	return op.wrapped.WriteAt(context.Background(), b, o)
}

func (op *checkingObjectProxy) Truncate(n uint64) error {
	op.wrapped.CheckInvariants()
	defer op.wrapped.CheckInvariants()
	return op.wrapped.Truncate(context.Background(), n)
}

func (op *checkingObjectProxy) Sync() (uint64, error) {
	op.wrapped.CheckInvariants()
	defer op.wrapped.CheckInvariants()
	return op.wrapped.Sync(context.Background())
}

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type ObjectProxyTest struct {
	objectName string
	bucket     mock_gcs.MockBucket
	op         checkingObjectProxy
}

func (t *ObjectProxyTest) setUp(ti *TestInfo, srcGeneration uint64) {
	t.objectName = "some/object"
	t.bucket = mock_gcs.NewMockBucket(ti.MockController, "bucket")

	var err error
	t.op.wrapped, err = gcsproxy.NewObjectProxy(
		context.Background(),
		t.bucket,
		t.objectName,
		srcGeneration)

	if err != nil {
		panic(err)
	}
}

////////////////////////////////////////////////////////////////////////
// No source object
////////////////////////////////////////////////////////////////////////

// A test whose initial conditions are a fresh object proxy without a source
// object set.
type NoSourceObjectTest struct {
	ObjectProxyTest
}

var _ SetUpInterface = &NoSourceObjectTest{}

func init() { RegisterTestSuite(&NoSourceObjectTest{}) }

func (t *NoSourceObjectTest) SetUp(ti *TestInfo) {
	t.ObjectProxyTest.setUp(ti, 0)
}

func (t *NoSourceObjectTest) Name() {
	ExpectEq(t.objectName, t.op.Name())
}

func (t *NoSourceObjectTest) Read_InitialState() {
	buf := make([]byte, 1024)
	n, err := t.op.ReadAt(buf, 0)

	ExpectEq(io.EOF, err)
	ExpectEq(0, n)
}

func (t *NoSourceObjectTest) WriteToEndOfObjectThenRead() {
	var buf []byte
	var n int
	var err error

	// Extend the object by writing twice.
	n, err = t.op.WriteAt([]byte("taco"), 0)
	AssertEq(nil, err)
	AssertEq(len("taco"), n)

	n, err = t.op.WriteAt([]byte("burrito"), int64(len("taco")))
	AssertEq(nil, err)
	AssertEq(len("burrito"), n)

	// Read the whole thing.
	buf = make([]byte, 1024)
	n, err = t.op.ReadAt(buf, 0)

	AssertEq(io.EOF, err)
	ExpectEq(len("tacoburrito"), n)
	ExpectEq("tacoburrito", string(buf[:n]))

	// Read a range in the middle.
	buf = make([]byte, 4)
	n, err = t.op.ReadAt(buf, 3)

	AssertEq(nil, err)
	ExpectEq(4, n)
	ExpectEq("obur", string(buf[:n]))
}

func (t *NoSourceObjectTest) WritePastEndOfObjectThenRead() {
	var n int
	var err error
	var buf []byte

	// Extend the object by writing past its end.
	n, err = t.op.WriteAt([]byte("taco"), 2)
	AssertEq(nil, err)
	AssertEq(len("taco"), n)

	// Read the whole thing.
	buf = make([]byte, 1024)
	n, err = t.op.ReadAt(buf, 0)

	AssertEq(io.EOF, err)
	ExpectEq(2+len("taco"), n)
	ExpectEq("\x00\x00taco", string(buf[:n]))

	// Read a range in the middle.
	buf = make([]byte, 4)
	n, err = t.op.ReadAt(buf, 1)

	AssertEq(nil, err)
	ExpectEq(4, n)
	ExpectEq("\x00tac", string(buf[:n]))
}

func (t *NoSourceObjectTest) WriteWithinObjectThenRead() {
	var n int
	var err error
	var buf []byte

	// Write several bytes to extend the object.
	n, err = t.op.WriteAt([]byte("00000"), 0)
	AssertEq(nil, err)
	AssertEq(len("00000"), n)

	// Overwrite some in the middle.
	n, err = t.op.WriteAt([]byte("11"), 1)
	AssertEq(nil, err)
	AssertEq(len("11"), n)

	// Read the whole thing.
	buf = make([]byte, 1024)
	n, err = t.op.ReadAt(buf, 0)

	AssertEq(io.EOF, err)
	ExpectEq(len("01100"), n)
	ExpectEq("01100", string(buf[:n]))
}

func (t *NoSourceObjectTest) GrowByTruncating() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Sync_NoInteractions() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Sync_ReadCallsOnly() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Sync_AfterWriting() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Sync_AfterTruncating() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Sync_CreateObjectFails() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Sync_CreateObjectSaysPreconditionFailed() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Sync_Successful() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Stat_CallsBucket() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Stat_BucketFails() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Stat_InitialState() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Stat_AfterShortening() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Stat_AfterGrowing() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Stat_AfterReading() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Stat_AfterWriting() {
	AssertTrue(false, "TODO")
}

func (t *NoSourceObjectTest) Stat_Clobbered() {
	AssertTrue(false, "TODO")
}

////////////////////////////////////////////////////////////////////////
// Source object present
////////////////////////////////////////////////////////////////////////

// A test whose initial conditions are an object proxy branching from a source
// object in the bucket.
type SourceObjectPresentTest struct {
	ObjectProxyTest
	sourceObject *storage.Object
}

var _ SetUpInterface = &SourceObjectPresentTest{}

func init() { RegisterTestSuite(&SourceObjectPresentTest{}) }

func (t *SourceObjectPresentTest) SetUp(ti *TestInfo) {
	t.ObjectProxyTest.setUp(ti, 123)
}

func (t *SourceObjectPresentTest) Read_CallsNewReader() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Read_NewReaderFails() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Read_NewReaderSucceeds() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Write_CallsNewReader() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Write_NewReaderFails() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Write_NewReaderSucceeds() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Truncate_CallsNewReader() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Truncate_NewReaderFails() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Truncate_NewReaderSucceeds() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Sync_NoInteractions() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Sync_CallsCreateObject() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Stat_CallsBucket() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Stat_BucketFails() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Stat_BucketSaysNotFound() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Stat_InitialState() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Stat_AfterShortening() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Stat_AfterGrowing() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Stat_AfterReading() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Stat_AfterWriting() {
	AssertTrue(false, "TODO")
}

func (t *SourceObjectPresentTest) Stat_Clobbered() {
	AssertTrue(false, "TODO")
}
<|endoftext|>