<commit_before>package models

import (
	"time"

	"gopkg.in/mgo.v2/bson"
)

type User struct {
	ObjectId       bson.ObjectId `bson:"_id" json:"_id"`
	Uid            int           `bson:"uid" json:"uid"`
	Email          string        `bson:"email" json:"email"`
	SanitizedEmail string        `bson:"sanitizedEmail" json:"sanitizedEmail"`
	LastLoginDate  time.Time     `bson:"lastLoginDate,omitempty" json:"lastLoginDate"`
	RegisteredAt   time.Time     `bson:"registeredAt" json:"registeredAt"`
	BlockedUntil   time.Time     `bson:"blockedUntil,omitempty" json:"blockedUntil"`

	// TODO left this for consistency, but should be converted into Username
	Name string `bson:"username" json:"username"`

	OldName  string `bson:"oldUsername" json:"oldUserName"`
	Password string `bson:"password" json:"password"`
	Status   string `bson:"status" json:"status"`
	Salt     string `bson:"salt" json:"salt"`
	Shell    string `bson:"shell" json:"shell"`
	SshKeys  []struct {
		Title string `bson:"title"`
		Key   string `bson:"key"`
	} `bson:"sshKeys"`
	OnlineStatus struct {
		Actual string `bson:"actual"`
	} `bson:"onlineStatus"`

	BlockedReason string `bson:"blockedReason" json:"blockedReason"`

	EmailFrequency *EmailFrequency `bson:"emailFrequency" json:"emailFrequency"`
	Inactive       *UserInactive   `bson:"inactive,omitempty" json:"inactive"`
	ForeignAuth    ForeignAuth     `bson:"foreignAuth,omitempty" json:"-"`
}

type EmailFrequency struct {
	Global            bool   `bson:"global"`
	Daily             bool   `bson:"daily"`
	PrivateMessage    bool   `bson:"privateMessage"`
	Follow            bool   `bson:"followActions"`
	Comment           bool   `bson:"comment"`
	Like              bool   `bson:"likeActivities"`
	GroupInvite       bool   `bson:"groupInvite"`
	GroupRequest      bool   `bson:"groupRequest"`
	GroupApproved     bool   `bson:"groupApproved"`
	Join              bool   `bson:"groupJoined"`
	Leave             bool   `bson:"groupLeft"`
	Mention           bool   `bson:"mention"`
	NotificationDelay string `bson:"pmNotificationDelay"`
}

type UserInactive struct {
	Warning    string               `bson:"warning" json:"warning"`
	Assigned   bool                 `bson:"assigned" json:"assigned"`
	AssignedAt time.Time            `bson:"assignedAt" json:"assignedAt"`
	ModifiedAt time.Time            `bson:"modifiedAt" json:"modifiedAt"`
	Warnings   map[string]time.Time `bson:"warnings,omitempty" json:"warnings"`
}

type ForeignAuth struct {
	Github Github `bson:"github" json:"-"`
	Slack  Slack  `bson:"slack" json:"-"`
}

type Slack struct {
	Token    string `bson:"token" json:"-"`
	Email    string
	Username string
	Scope    string
}

type Github struct {
	Token    string `bson:"token" json:"-"`
	Email    string
	Username string
	Scope    string
}

func (f ForeignAuth) GetAccessToken(name string) string {
	switch name {
	case "github":
		return f.Github.Token
	case "slack":
		return f.Slack.Token
	default:
		return ""
	}
}
<commit_msg>JUser: add multi group support for slack token<commit_after>package models

import (
	"time"

	"gopkg.in/mgo.v2/bson"
)

type User struct {
	ObjectId       bson.ObjectId `bson:"_id" json:"_id"`
	Uid            int           `bson:"uid" json:"uid"`
	Email          string        `bson:"email" json:"email"`
	SanitizedEmail string        `bson:"sanitizedEmail" json:"sanitizedEmail"`
	LastLoginDate  time.Time     `bson:"lastLoginDate,omitempty" json:"lastLoginDate"`
	RegisteredAt   time.Time     `bson:"registeredAt" json:"registeredAt"`
	BlockedUntil   time.Time     `bson:"blockedUntil,omitempty" json:"blockedUntil"`

	// TODO left this for consistency, but should be converted into Username
	Name string `bson:"username" json:"username"`

	OldName  string `bson:"oldUsername" json:"oldUserName"`
	Password string `bson:"password" json:"password"`
	Status   string `bson:"status" json:"status"`
	Salt     string `bson:"salt" json:"salt"`
	Shell    string `bson:"shell" json:"shell"`
	SshKeys  []struct {
		Title string `bson:"title"`
		Key   string `bson:"key"`
	} `bson:"sshKeys"`
	OnlineStatus struct {
		Actual string `bson:"actual"`
	} `bson:"onlineStatus"`

	BlockedReason string `bson:"blockedReason" json:"blockedReason"`

	EmailFrequency *EmailFrequency `bson:"emailFrequency" json:"emailFrequency"`
	Inactive       *UserInactive   `bson:"inactive,omitempty" json:"inactive"`
	ForeignAuth    ForeignAuth     `bson:"foreignAuth,omitempty" json:"-"`
}

type EmailFrequency struct {
	Global            bool   `bson:"global"`
	Daily             bool   `bson:"daily"`
	PrivateMessage    bool   `bson:"privateMessage"`
	Follow            bool   `bson:"followActions"`
	Comment           bool   `bson:"comment"`
	Like              bool   `bson:"likeActivities"`
	GroupInvite       bool   `bson:"groupInvite"`
	GroupRequest      bool   `bson:"groupRequest"`
	GroupApproved     bool   `bson:"groupApproved"`
	Join              bool   `bson:"groupJoined"`
	Leave             bool   `bson:"groupLeft"`
	Mention           bool   `bson:"mention"`
	NotificationDelay string `bson:"pmNotificationDelay"`
}

type UserInactive struct {
	Warning    string               `bson:"warning" json:"warning"`
	Assigned   bool                 `bson:"assigned" json:"assigned"`
	AssignedAt time.Time            `bson:"assignedAt" json:"assignedAt"`
	ModifiedAt time.Time            `bson:"modifiedAt" json:"modifiedAt"`
	Warnings   map[string]time.Time `bson:"warnings,omitempty" json:"warnings"`
}

type ForeignAuth struct {
	Github Github           `bson:"github" json:"-"`
	Slack  map[string]Slack `bson:"slack" json:"-"`
}

type Slack struct {
	Token    string `bson:"token" json:"-"`
	Email    string
	Username string
	Scope    string
}

type Github struct {
	Token    string `bson:"token" json:"-"`
	Email    string
	Username string
	Scope    string
}

func (f ForeignAuth) GetAccessToken(name string) string {
	switch name {
	case "github":
		return f.Github.Token
	default:
		return ""
	}
}
<|endoftext|>


<commit_before>package decimal

import (
	"log"
	"math"
	"math/big"
	"testing"
)

func TestIssue20(t *testing.T) {
	x := New(10240000000000, 0)
	x.Mul(x, New(976563, 9))
	if v, _ := x.Int64(); v != 10000005120 {
		t.Fatal("error int64: ", v, x.Int(nil).Int64())
	}
}

func TestIssue65(t *testing.T) {
	const expected = "999999999000000000000000000000"
	r, _ := new(big.Rat).SetString(expected)
	r2 := new(Big).SetRat(r).Rat(nil)
	if r.Cmp(r2) != 0 {
		t.Fatalf("expected %q, got %q", r, r2)
	}
}

func TestIssue71(t *testing.T) {
	x, _ := new(Big).SetString("-433997231707950814777029946371807573425840064343095193931191306942897586882.200850175108941825587256711340679426793690849230895605323379098449524300541372392806145820741928")
	y := New(5, 0)
	ctx := Context{RoundingMode: ToZero, Precision: 364}

	z := new(Big)
	ctx.Quo(z, x, y)

	r, _ := new(Big).SetString("-86799446341590162955405989274361514685168012868619038786238261388579517376.4401700350217883651174513422681358853587381698461791210646758196899048601082744785612291641483856")
	if z.Cmp(r) != 0 || z.Scale() != r.Scale() {
		t.Fatalf(`Quo(%s, %s)
wanted: %s (%d)
got   : %s (%d)
`, x, y, r, -r.Scale(), z, -z.Scale())
	}
}

func TestIssue72(t *testing.T) {
	x, _ := new(Big).SetString("-8.45632792449080367076920780185655231664817924617196338687858969707575095137356626097186102468204972266270655439471710162223657196797091956190618036249568250856310899052975275153410779062120467574000771085625757386351708361318971283364474972153263288762761014798575650687906566E+474")
	y, _ := new(Big).SetString("4394389707820271499500265597691058417332780189928068605060129835915231607024733174128123086028964659911263805538968425927408117535552905751413991847682423230507052480632597367974353369255973450023914.06480266537851511912348920528179447782332532576762774258658035423323623047681531444628650113938865866058071268742035039370988065347285125745597527162817805470262344343643075954571122548882320506470664701832116848314413975179616459225485097673077072340532232446317251990415268245406080149594165531067657351225251495644780695372152557650401209918010537469259193951365404947434164664325966741900020673085975334136592934327584453217952431999450960191719318690339387778325911")
	z := new(Big)
	ctx := Context{Precision: 276}
	ctx.Rem(z, x, y)
	if !z.IsNaN(+1) {
		t.Fatalf(`Rem(%s, %s)
wanted: NaN
got   : %s
`, x, y, z)
	}
}

func TestIssue99(t *testing.T) {
	bad := &Big{compact: 11234567890123457890, exp: -20, precision: 20}
	ref := &Big{compact: 2, exp: -1, precision: 1}

	cmp := bad.Cmp(ref)
	if cmp != -1 {
		t.Errorf("expected %s smaller than %s\n", bad.String(), ref.String())
	}
	cmp = ref.Cmp(bad)
	if cmp != 1 {
		t.Errorf("expected %s larger than %s\n", ref.String(), bad.String())
	}
}

func TestIssue104(t *testing.T) {
	x := WithContext(Context128).SetUint64(math.MaxUint64)
	y, ok := x.Uint64()
	if !ok {
		t.Error("failed to convert back")
	}
	if y != math.MaxUint64 {
		t.Errorf("conversion 'succeeded' but the value failed to make the round trip - got %d", y)
	}
}

func TestIssue105(t *testing.T) {
	var b Big
	b.SetString("6190.000000000000")
	if _, ok := b.Float64(); !ok {
		log.Fatalf("6190 should fit in a float just fine")
	}
}
<commit_msg>remove log from issues_Test.go<commit_after>package decimal

import (
	"math"
	"math/big"
	"testing"
)

func TestIssue20(t *testing.T) {
	x := New(10240000000000, 0)
	x.Mul(x, New(976563, 9))
	if v, _ := x.Int64(); v != 10000005120 {
		t.Fatal("error int64: ", v, x.Int(nil).Int64())
	}
}

func TestIssue65(t *testing.T) {
	const expected = "999999999000000000000000000000"
	r, _ := new(big.Rat).SetString(expected)
	r2 := new(Big).SetRat(r).Rat(nil)
	if r.Cmp(r2) != 0 {
		t.Fatalf("expected %q, got %q", r, r2)
	}
}

func TestIssue71(t *testing.T) {
	x, _ := new(Big).SetString("-433997231707950814777029946371807573425840064343095193931191306942897586882.200850175108941825587256711340679426793690849230895605323379098449524300541372392806145820741928")
	y := New(5, 0)
	ctx := Context{RoundingMode: ToZero, Precision: 364}

	z := new(Big)
	ctx.Quo(z, x, y)

	r, _ := new(Big).SetString("-86799446341590162955405989274361514685168012868619038786238261388579517376.4401700350217883651174513422681358853587381698461791210646758196899048601082744785612291641483856")
	if z.Cmp(r) != 0 || z.Scale() != r.Scale() {
		t.Fatalf(`Quo(%s, %s)
wanted: %s (%d)
got   : %s (%d)
`, x, y, r, -r.Scale(), z, -z.Scale())
	}
}

func TestIssue72(t *testing.T) {
	x, _ := new(Big).SetString("-8.45632792449080367076920780185655231664817924617196338687858969707575095137356626097186102468204972266270655439471710162223657196797091956190618036249568250856310899052975275153410779062120467574000771085625757386351708361318971283364474972153263288762761014798575650687906566E+474")
	y, _ := new(Big).SetString("4394389707820271499500265597691058417332780189928068605060129835915231607024733174128123086028964659911263805538968425927408117535552905751413991847682423230507052480632597367974353369255973450023914.06480266537851511912348920528179447782332532576762774258658035423323623047681531444628650113938865866058071268742035039370988065347285125745597527162817805470262344343643075954571122548882320506470664701832116848314413975179616459225485097673077072340532232446317251990415268245406080149594165531067657351225251495644780695372152557650401209918010537469259193951365404947434164664325966741900020673085975334136592934327584453217952431999450960191719318690339387778325911")
	z := new(Big)
	ctx := Context{Precision: 276}
	ctx.Rem(z, x, y)
	if !z.IsNaN(+1) {
		t.Fatalf(`Rem(%s, %s)
wanted: NaN
got   : %s
`, x, y, z)
	}
}

func TestIssue99(t *testing.T) {
	bad := &Big{compact: 11234567890123457890, exp: -20, precision: 20}
	ref := &Big{compact: 2, exp: -1, precision: 1}

	cmp := bad.Cmp(ref)
	if cmp != -1 {
		t.Errorf("expected %s smaller than %s\n", bad.String(), ref.String())
	}
	cmp = ref.Cmp(bad)
	if cmp != 1 {
		t.Errorf("expected %s larger than %s\n", ref.String(), bad.String())
	}
}

func TestIssue104(t *testing.T) {
	x := WithContext(Context128).SetUint64(math.MaxUint64)
	y, ok := x.Uint64()
	if !ok {
		t.Error("failed to convert back")
	}
	if y != math.MaxUint64 {
		t.Errorf("conversion 'succeeded' but the value failed to make the round trip - got %d", y)
	}
}

func TestIssue105(t *testing.T) {
	var b Big
	b.SetString("6190.000000000000")
	if _, ok := b.Float64(); !ok {
		t.Fatalf("6190 should fit in a float just fine")
	}
}
<|endoftext|>


<commit_before>//  Copyright (c) 2014 Couchbase, Inc.
//
// 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 searcher

import (
	"math"

	"github.com/blevesearch/bleve/index"
	"github.com/blevesearch/bleve/search"
)

type PhraseSearcher struct {
	indexReader  index.IndexReader
	mustSearcher *ConjunctionSearcher
	queryNorm    float64
	currMust     *search.DocumentMatch
	slop         int
	terms        []string
	initialized  bool
}

func NewPhraseSearcher(indexReader index.IndexReader, mustSearcher *ConjunctionSearcher, terms []string) (*PhraseSearcher, error) {
	// build our searcher
	rv := PhraseSearcher{
		indexReader:  indexReader,
		mustSearcher: mustSearcher,
		terms:        terms,
	}
	rv.computeQueryNorm()
	return &rv, nil
}

func (s *PhraseSearcher) computeQueryNorm() {
	// first calculate sum of squared weights
	sumOfSquaredWeights := 0.0
	if s.mustSearcher != nil {
		sumOfSquaredWeights += s.mustSearcher.Weight()
	}

	// now compute query norm from this
	s.queryNorm = 1.0 / math.Sqrt(sumOfSquaredWeights)
	// finally tell all the downstream searchers the norm
	if s.mustSearcher != nil {
		s.mustSearcher.SetQueryNorm(s.queryNorm)
	}
}

func (s *PhraseSearcher) initSearchers(ctx *search.SearchContext) error {
	err := s.advanceNextMust(ctx)
	if err != nil {
		return err
	}

	s.initialized = true
	return nil
}

func (s *PhraseSearcher) advanceNextMust(ctx *search.SearchContext) error {
	var err error

	if s.mustSearcher != nil {
		s.currMust, err = s.mustSearcher.Next(ctx)
		if err != nil {
			return err
		}
	}

	return nil
}

func (s *PhraseSearcher) Weight() float64 {
	return s.mustSearcher.Weight()
}

func (s *PhraseSearcher) SetQueryNorm(qnorm float64) {
	s.mustSearcher.SetQueryNorm(qnorm)
}

func (s *PhraseSearcher) Next(ctx *search.SearchContext) (*search.DocumentMatch, error) {
	if !s.initialized {
		err := s.initSearchers(ctx)
		if err != nil {
			return nil, err
		}
	}

	var rv *search.DocumentMatch
	for s.currMust != nil {
		rvftlm := make(search.FieldTermLocationMap, 0)
		freq := 0
		firstTerm := s.terms[0]
		for field, termLocMap := range s.currMust.Locations {
			locations, ok := termLocMap[firstTerm]
			if !ok {
				continue
			}

			rvtlm := make(search.TermLocationMap, 0)

		OUTER:
			for _, location := range locations {
				crvtlm := make(search.TermLocationMap, 0)
				crvtlm.AddLocation(firstTerm, location)
			INNER:
				for i := 1; i < len(s.terms); i++ {
					nextTerm := s.terms[i]
					if nextTerm == "" {
						continue
					}
					// look through all these term locations
					// to try and find the correct offsets
					nextLocations, ok := termLocMap[nextTerm]
					if !ok {
						continue OUTER
					}
					for _, nextLocation := range nextLocations {
						if nextLocation.Pos == location.Pos+float64(i) && nextLocation.SameArrayElement(location) {
							// found a location match for this term
							crvtlm.AddLocation(nextTerm, nextLocation)
							continue INNER
						}
					}
					// if we got here we didn't find a location match for this term
					continue OUTER
				}
				// if we got here all the terms matched
				freq++
				search.MergeTermLocationMaps(rvtlm, crvtlm)
				rvftlm[field] = rvtlm
			}
		}

		if freq > 0 {
			// return match
			rv = s.currMust
			rv.Locations = rvftlm
			err := s.advanceNextMust(ctx)
			if err != nil {
				return nil, err
			}
			return rv, nil
		}

		err := s.advanceNextMust(ctx)
		if err != nil {
			return nil, err
		}
	}

	return nil, nil
}

func (s *PhraseSearcher) Advance(ctx *search.SearchContext, ID index.IndexInternalID) (*search.DocumentMatch, error) {
	if !s.initialized {
		err := s.initSearchers(ctx)
		if err != nil {
			return nil, err
		}
	}
	var err error
	s.currMust, err = s.mustSearcher.Advance(ctx, ID)
	if err != nil {
		return nil, err
	}
	return s.Next(ctx)
}

func (s *PhraseSearcher) Count() uint64 {
	// for now return a worst case
	return s.mustSearcher.Count()
}

func (s *PhraseSearcher) Close() error {
	if s.mustSearcher != nil {
		err := s.mustSearcher.Close()
		if err != nil {
			return err
		}
	}
	return nil
}

func (s *PhraseSearcher) Min() int {
	return 0
}

func (s *PhraseSearcher) DocumentMatchPoolSize() int {
	return s.mustSearcher.DocumentMatchPoolSize() + 1
}
<commit_msg>refactor phrase search into seprate methods<commit_after>//  Copyright (c) 2014 Couchbase, Inc.
//
// 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 searcher

import (
	"math"

	"github.com/blevesearch/bleve/index"
	"github.com/blevesearch/bleve/search"
)

type PhraseSearcher struct {
	indexReader  index.IndexReader
	mustSearcher *ConjunctionSearcher
	queryNorm    float64
	currMust     *search.DocumentMatch
	slop         int
	terms        []string
	initialized  bool
}

func NewPhraseSearcher(indexReader index.IndexReader, mustSearcher *ConjunctionSearcher, terms []string) (*PhraseSearcher, error) {
	// build our searcher
	rv := PhraseSearcher{
		indexReader:  indexReader,
		mustSearcher: mustSearcher,
		terms:        terms,
	}
	rv.computeQueryNorm()
	return &rv, nil
}

func (s *PhraseSearcher) computeQueryNorm() {
	// first calculate sum of squared weights
	sumOfSquaredWeights := 0.0
	if s.mustSearcher != nil {
		sumOfSquaredWeights += s.mustSearcher.Weight()
	}

	// now compute query norm from this
	s.queryNorm = 1.0 / math.Sqrt(sumOfSquaredWeights)
	// finally tell all the downstream searchers the norm
	if s.mustSearcher != nil {
		s.mustSearcher.SetQueryNorm(s.queryNorm)
	}
}

func (s *PhraseSearcher) initSearchers(ctx *search.SearchContext) error {
	err := s.advanceNextMust(ctx)
	if err != nil {
		return err
	}

	s.initialized = true
	return nil
}

func (s *PhraseSearcher) advanceNextMust(ctx *search.SearchContext) error {
	var err error

	if s.mustSearcher != nil {
		s.currMust, err = s.mustSearcher.Next(ctx)
		if err != nil {
			return err
		}
	}

	return nil
}

func (s *PhraseSearcher) Weight() float64 {
	return s.mustSearcher.Weight()
}

func (s *PhraseSearcher) SetQueryNorm(qnorm float64) {
	s.mustSearcher.SetQueryNorm(qnorm)
}

func (s *PhraseSearcher) Next(ctx *search.SearchContext) (*search.DocumentMatch, error) {
	if !s.initialized {
		err := s.initSearchers(ctx)
		if err != nil {
			return nil, err
		}
	}

	for s.currMust != nil {
		rv := s.checkCurrMustMatch(ctx)
		if rv != nil {
			// prepare for next iteration
			err := s.advanceNextMust(ctx)
			if err != nil {
				return nil, err
			}
			return rv, nil
		}

		err := s.advanceNextMust(ctx)
		if err != nil {
			return nil, err
		}
	}

	return nil, nil
}

// checkCurrMustMatch is soley concerned with determining if the DocumentMatch
// pointed to by s.currMust (which satisifies the pre-condition searcher)
// also satisfies the phase constraints.  if so, it returns a DocumentMatch
// for this document, otherwise nil
func (s *PhraseSearcher) checkCurrMustMatch(ctx *search.SearchContext) *search.DocumentMatch {
	rvftlm := make(search.FieldTermLocationMap, 0)
	freq := 0
	// typically we would expect there to only actually be results in
	// one field, but we allow for this to not be the case
	// but, we note that phrase constraints can only be satisfied within
	// a single field, so we can check them each independently
	for field := range s.currMust.Locations {

		f, rvtlm := s.checkCurrMustMatchField(ctx, field)
		if f > 0 {
			freq += f
			rvftlm[field] = rvtlm
		}
	}

	if freq > 0 {
		// return match
		rv := s.currMust
		rv.Locations = rvftlm
		return rv
	}

	return nil
}

// checkCurrMustMatchField is soley concerned with determining if one particular
// field within the currMust DocumentMatch Locations satisfies the phase
// constraints (possibly more than once).  if so, the number of times it was
// satisfied, and these locations are returned.  otherwise 0 and either
// a nil or empty TermLocationMap
func (s *PhraseSearcher) checkCurrMustMatchField(ctx *search.SearchContext, field string) (int, search.TermLocationMap) {
	firstTerm := s.terms[0]
	freq := 0
	termLocMap := s.currMust.Locations[field]
	locations, ok := termLocMap[firstTerm]
	if !ok {
		return 0, nil
	}

	rvtlm := make(search.TermLocationMap, 0)

OUTER:
	for _, location := range locations {
		crvtlm := make(search.TermLocationMap, 0)
		crvtlm.AddLocation(firstTerm, location)
	INNER:
		for i := 1; i < len(s.terms); i++ {
			nextTerm := s.terms[i]
			if nextTerm == "" {
				continue
			}
			// look through all these term locations
			// to try and find the correct offsets
			nextLocations, ok := termLocMap[nextTerm]
			if !ok {
				continue OUTER
			}
			for _, nextLocation := range nextLocations {
				if nextLocation.Pos == location.Pos+float64(i) && nextLocation.SameArrayElement(location) {
					// found a location match for this term
					crvtlm.AddLocation(nextTerm, nextLocation)
					continue INNER
				}
			}
			// if we got here we didn't find a location match for this term
			continue OUTER
		}
		// if we got here all the terms matched
		freq++
		search.MergeTermLocationMaps(rvtlm, crvtlm)
	}

	return freq, rvtlm
}

func (s *PhraseSearcher) Advance(ctx *search.SearchContext, ID index.IndexInternalID) (*search.DocumentMatch, error) {
	if !s.initialized {
		err := s.initSearchers(ctx)
		if err != nil {
			return nil, err
		}
	}
	var err error
	s.currMust, err = s.mustSearcher.Advance(ctx, ID)
	if err != nil {
		return nil, err
	}
	return s.Next(ctx)
}

func (s *PhraseSearcher) Count() uint64 {
	// for now return a worst case
	return s.mustSearcher.Count()
}

func (s *PhraseSearcher) Close() error {
	if s.mustSearcher != nil {
		err := s.mustSearcher.Close()
		if err != nil {
			return err
		}
	}
	return nil
}

func (s *PhraseSearcher) Min() int {
	return 0
}

func (s *PhraseSearcher) DocumentMatchPoolSize() int {
	return s.mustSearcher.DocumentMatchPoolSize() + 1
}
<|endoftext|>


<commit_before>package snapshot

import (
	"bytes"
	"encoding/json"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"

	"github.com/docker/notary/server/storage"
	"github.com/docker/notary/tuf/data"
	"github.com/docker/notary/tuf/signed"
)

func TestSnapshotExpired(t *testing.T) {
	sn := &data.SignedSnapshot{
		Signatures: nil,
		Signed: data.Snapshot{
			Expires: time.Now().AddDate(-1, 0, 0),
		},
	}
	assert.True(t, snapshotExpired(sn), "Snapshot should have expired")
}

func TestSnapshotNotExpired(t *testing.T) {
	sn := &data.SignedSnapshot{
		Signatures: nil,
		Signed: data.Snapshot{
			Expires: time.Now().AddDate(1, 0, 0),
		},
	}
	assert.False(t, snapshotExpired(sn), "Snapshot should NOT have expired")
}

func TestGetSnapshotKeyCreate(t *testing.T) {
	store := storage.NewMemStorage()
	crypto := signed.NewEd25519()
	k, err := GetOrCreateSnapshotKey("gun", store, crypto, data.ED25519Key)
	assert.Nil(t, err, "Expected nil error")
	assert.NotNil(t, k, "Key should not be nil")

	k2, err := GetOrCreateSnapshotKey("gun", store, crypto, data.ED25519Key)

	assert.Nil(t, err, "Expected nil error")

	// trying to get the same key again should return the same value
	assert.Equal(t, k, k2, "Did not receive same key when attempting to recreate.")
	assert.NotNil(t, k2, "Key should not be nil")
}

func TestGetSnapshotKeyExisting(t *testing.T) {
	store := storage.NewMemStorage()
	crypto := signed.NewEd25519()
	key, err := crypto.Create(data.CanonicalSnapshotRole, data.ED25519Key)
	assert.NoError(t, err)

	store.SetKey("gun", data.CanonicalSnapshotRole, data.ED25519Key, key.Public())

	k, err := GetOrCreateSnapshotKey("gun", store, crypto, data.ED25519Key)
	assert.Nil(t, err, "Expected nil error")
	assert.NotNil(t, k, "Key should not be nil")
	assert.Equal(t, key, k, "Did not receive same key when attempting to recreate.")
	assert.NotNil(t, k, "Key should not be nil")

	k2, err := GetOrCreateSnapshotKey("gun", store, crypto, data.ED25519Key)

	assert.Nil(t, err, "Expected nil error")

	// trying to get the same key again should return the same value
	assert.Equal(t, k, k2, "Did not receive same key when attempting to recreate.")
	assert.NotNil(t, k2, "Key should not be nil")
}

type keyStore struct {
	getCalled bool
	k         data.PublicKey
}

func (ks *keyStore) GetKey(gun, role string) (string, []byte, error) {
	defer func() { ks.getCalled = true }()
	if ks.getCalled {
		return ks.k.Algorithm(), ks.k.Public(), nil
	}
	return "", nil, &storage.ErrNoKey{}
}

func (ks keyStore) SetKey(gun, role, algorithm string, public []byte) error {
	return &storage.ErrKeyExists{}
}

func TestGetSnapshotKeyExistsOnSet(t *testing.T) {
	crypto := signed.NewEd25519()
	key, err := crypto.Create(data.CanonicalSnapshotRole, data.ED25519Key)
	assert.NoError(t, err)
	store := &keyStore{k: key}

	k, err := GetOrCreateSnapshotKey("gun", store, crypto, data.ED25519Key)
	assert.Nil(t, err, "Expected nil error")
	assert.NotNil(t, k, "Key should not be nil")
	assert.Equal(t, key, k, "Did not receive same key when attempting to recreate.")
	assert.NotNil(t, k, "Key should not be nil")

	k2, err := GetOrCreateSnapshotKey("gun", store, crypto, data.ED25519Key)

	assert.Nil(t, err, "Expected nil error")

	// trying to get the same key again should return the same value
	assert.Equal(t, k, k2, "Did not receive same key when attempting to recreate.")
	assert.NotNil(t, k2, "Key should not be nil")
}

func TestRoleExpired(t *testing.T) {
	meta := data.FileMeta{
		Hashes: data.Hashes{
			"sha256": []byte{1},
		},
	}
	newData := []byte{2}
	res, _ := roleExpired(newData, meta)
	assert.True(t, res)
}

func TestRoleNotExpired(t *testing.T) {
	newData := []byte{2}
	currMeta, err := data.NewFileMeta(bytes.NewReader(newData), "sha256")
	assert.NoError(t, err)

	meta := data.FileMeta{
		Hashes: data.Hashes{
			"sha256": currMeta.Hashes["sha256"],
		},
	}

	res, _ := roleExpired(newData, meta)
	assert.False(t, res)
}

func TestGetSnapshotNotExists(t *testing.T) {
	store := storage.NewMemStorage()
	crypto := signed.NewEd25519()

	_, err := GetOrCreateSnapshot("gun", store, crypto)
	assert.Error(t, err)
}

func TestGetSnapshotCurrValid(t *testing.T) {
	store := storage.NewMemStorage()
	crypto := signed.NewEd25519()

	_, err := GetOrCreateSnapshotKey("gun", store, crypto, data.ED25519Key)

	newData := []byte{2}
	currMeta, err := data.NewFileMeta(bytes.NewReader(newData), "sha256")
	assert.NoError(t, err)

	snapshot := &data.SignedSnapshot{
		Signed: data.Snapshot{
			Expires: data.DefaultExpires(data.CanonicalSnapshotRole),
			Meta: data.Files{
				data.CanonicalRootRole: currMeta,
			},
		},
	}
	snapJSON, _ := json.Marshal(snapshot)

	// test when db is missing the role data
	store.UpdateCurrent("gun", storage.MetaUpdate{Role: "snapshot", Version: 0, Data: snapJSON})
	_, err = GetOrCreateSnapshot("gun", store, crypto)
	assert.NoError(t, err)

	// test when db has the role data
	store.UpdateCurrent("gun", storage.MetaUpdate{Role: "root", Version: 0, Data: newData})
	_, err = GetOrCreateSnapshot("gun", store, crypto)
	assert.NoError(t, err)

	// test when db role data is expired
	store.UpdateCurrent("gun", storage.MetaUpdate{Role: "root", Version: 1, Data: []byte{3}})
	_, err = GetOrCreateSnapshot("gun", store, crypto)
	assert.NoError(t, err)
}

func TestGetSnapshotCurrExpired(t *testing.T) {
	store := storage.NewMemStorage()
	crypto := signed.NewEd25519()

	_, err := GetOrCreateSnapshotKey("gun", store, crypto, data.ED25519Key)

	snapshot := &data.SignedSnapshot{}
	snapJSON, _ := json.Marshal(snapshot)

	store.UpdateCurrent("gun", storage.MetaUpdate{Role: "snapshot", Version: 0, Data: snapJSON})
	_, err = GetOrCreateSnapshot("gun", store, crypto)
	assert.NoError(t, err)
}

func TestGetSnapshotCurrCorrupt(t *testing.T) {
	store := storage.NewMemStorage()
	crypto := signed.NewEd25519()

	_, err := GetOrCreateSnapshotKey("gun", store, crypto, data.ED25519Key)

	snapshot := &data.SignedSnapshot{}
	snapJSON, _ := json.Marshal(snapshot)

	store.UpdateCurrent("gun", storage.MetaUpdate{Role: "snapshot", Version: 0, Data: snapJSON[1:]})
	_, err = GetOrCreateSnapshot("gun", store, crypto)
	assert.Error(t, err)
}
<commit_msg>adding comment to snapshot key insert race condition test per @cyli's request Signed-off-by: David Lawrence <david.lawrence@docker.com> (github: endophage)<commit_after>package snapshot

import (
	"bytes"
	"encoding/json"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"

	"github.com/docker/notary/server/storage"
	"github.com/docker/notary/tuf/data"
	"github.com/docker/notary/tuf/signed"
)

func TestSnapshotExpired(t *testing.T) {
	sn := &data.SignedSnapshot{
		Signatures: nil,
		Signed: data.Snapshot{
			Expires: time.Now().AddDate(-1, 0, 0),
		},
	}
	assert.True(t, snapshotExpired(sn), "Snapshot should have expired")
}

func TestSnapshotNotExpired(t *testing.T) {
	sn := &data.SignedSnapshot{
		Signatures: nil,
		Signed: data.Snapshot{
			Expires: time.Now().AddDate(1, 0, 0),
		},
	}
	assert.False(t, snapshotExpired(sn), "Snapshot should NOT have expired")
}

func TestGetSnapshotKeyCreate(t *testing.T) {
	store := storage.NewMemStorage()
	crypto := signed.NewEd25519()
	k, err := GetOrCreateSnapshotKey("gun", store, crypto, data.ED25519Key)
	assert.Nil(t, err, "Expected nil error")
	assert.NotNil(t, k, "Key should not be nil")

	k2, err := GetOrCreateSnapshotKey("gun", store, crypto, data.ED25519Key)

	assert.Nil(t, err, "Expected nil error")

	// trying to get the same key again should return the same value
	assert.Equal(t, k, k2, "Did not receive same key when attempting to recreate.")
	assert.NotNil(t, k2, "Key should not be nil")
}

func TestGetSnapshotKeyExisting(t *testing.T) {
	store := storage.NewMemStorage()
	crypto := signed.NewEd25519()
	key, err := crypto.Create(data.CanonicalSnapshotRole, data.ED25519Key)
	assert.NoError(t, err)

	store.SetKey("gun", data.CanonicalSnapshotRole, data.ED25519Key, key.Public())

	k, err := GetOrCreateSnapshotKey("gun", store, crypto, data.ED25519Key)
	assert.Nil(t, err, "Expected nil error")
	assert.NotNil(t, k, "Key should not be nil")
	assert.Equal(t, key, k, "Did not receive same key when attempting to recreate.")
	assert.NotNil(t, k, "Key should not be nil")

	k2, err := GetOrCreateSnapshotKey("gun", store, crypto, data.ED25519Key)

	assert.Nil(t, err, "Expected nil error")

	// trying to get the same key again should return the same value
	assert.Equal(t, k, k2, "Did not receive same key when attempting to recreate.")
	assert.NotNil(t, k2, "Key should not be nil")
}

type keyStore struct {
	getCalled bool
	k         data.PublicKey
}

func (ks *keyStore) GetKey(gun, role string) (string, []byte, error) {
	defer func() { ks.getCalled = true }()
	if ks.getCalled {
		return ks.k.Algorithm(), ks.k.Public(), nil
	}
	return "", nil, &storage.ErrNoKey{}
}

func (ks keyStore) SetKey(gun, role, algorithm string, public []byte) error {
	return &storage.ErrKeyExists{}
}

// Tests the race condition where the server is being asked to generate a new key
// by 2 parallel requests and the second insert to be executed by the DB fails
// due to duplicate key (gun + role). It should then return the key added by the
// first insert.
func TestGetSnapshotKeyExistsOnSet(t *testing.T) {
	crypto := signed.NewEd25519()
	key, err := crypto.Create(data.CanonicalSnapshotRole, data.ED25519Key)
	assert.NoError(t, err)
	store := &keyStore{k: key}

	k, err := GetOrCreateSnapshotKey("gun", store, crypto, data.ED25519Key)
	assert.Nil(t, err, "Expected nil error")
	assert.NotNil(t, k, "Key should not be nil")
	assert.Equal(t, key, k, "Did not receive same key when attempting to recreate.")
	assert.NotNil(t, k, "Key should not be nil")

	k2, err := GetOrCreateSnapshotKey("gun", store, crypto, data.ED25519Key)

	assert.Nil(t, err, "Expected nil error")

	// trying to get the same key again should return the same value
	assert.Equal(t, k, k2, "Did not receive same key when attempting to recreate.")
	assert.NotNil(t, k2, "Key should not be nil")
}

func TestRoleExpired(t *testing.T) {
	meta := data.FileMeta{
		Hashes: data.Hashes{
			"sha256": []byte{1},
		},
	}
	newData := []byte{2}
	res, _ := roleExpired(newData, meta)
	assert.True(t, res)
}

func TestRoleNotExpired(t *testing.T) {
	newData := []byte{2}
	currMeta, err := data.NewFileMeta(bytes.NewReader(newData), "sha256")
	assert.NoError(t, err)

	meta := data.FileMeta{
		Hashes: data.Hashes{
			"sha256": currMeta.Hashes["sha256"],
		},
	}

	res, _ := roleExpired(newData, meta)
	assert.False(t, res)
}

func TestGetSnapshotNotExists(t *testing.T) {
	store := storage.NewMemStorage()
	crypto := signed.NewEd25519()

	_, err := GetOrCreateSnapshot("gun", store, crypto)
	assert.Error(t, err)
}

func TestGetSnapshotCurrValid(t *testing.T) {
	store := storage.NewMemStorage()
	crypto := signed.NewEd25519()

	_, err := GetOrCreateSnapshotKey("gun", store, crypto, data.ED25519Key)

	newData := []byte{2}
	currMeta, err := data.NewFileMeta(bytes.NewReader(newData), "sha256")
	assert.NoError(t, err)

	snapshot := &data.SignedSnapshot{
		Signed: data.Snapshot{
			Expires: data.DefaultExpires(data.CanonicalSnapshotRole),
			Meta: data.Files{
				data.CanonicalRootRole: currMeta,
			},
		},
	}
	snapJSON, _ := json.Marshal(snapshot)

	// test when db is missing the role data
	store.UpdateCurrent("gun", storage.MetaUpdate{Role: "snapshot", Version: 0, Data: snapJSON})
	_, err = GetOrCreateSnapshot("gun", store, crypto)
	assert.NoError(t, err)

	// test when db has the role data
	store.UpdateCurrent("gun", storage.MetaUpdate{Role: "root", Version: 0, Data: newData})
	_, err = GetOrCreateSnapshot("gun", store, crypto)
	assert.NoError(t, err)

	// test when db role data is expired
	store.UpdateCurrent("gun", storage.MetaUpdate{Role: "root", Version: 1, Data: []byte{3}})
	_, err = GetOrCreateSnapshot("gun", store, crypto)
	assert.NoError(t, err)
}

func TestGetSnapshotCurrExpired(t *testing.T) {
	store := storage.NewMemStorage()
	crypto := signed.NewEd25519()

	_, err := GetOrCreateSnapshotKey("gun", store, crypto, data.ED25519Key)

	snapshot := &data.SignedSnapshot{}
	snapJSON, _ := json.Marshal(snapshot)

	store.UpdateCurrent("gun", storage.MetaUpdate{Role: "snapshot", Version: 0, Data: snapJSON})
	_, err = GetOrCreateSnapshot("gun", store, crypto)
	assert.NoError(t, err)
}

func TestGetSnapshotCurrCorrupt(t *testing.T) {
	store := storage.NewMemStorage()
	crypto := signed.NewEd25519()

	_, err := GetOrCreateSnapshotKey("gun", store, crypto, data.ED25519Key)

	snapshot := &data.SignedSnapshot{}
	snapJSON, _ := json.Marshal(snapshot)

	store.UpdateCurrent("gun", storage.MetaUpdate{Role: "snapshot", Version: 0, Data: snapJSON[1:]})
	_, err = GetOrCreateSnapshot("gun", store, crypto)
	assert.Error(t, err)
}
<|endoftext|>


<commit_before>// Copyright 2021 Google LLC. 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 provides a command line tool for sequencing entries in
// a serverless log.
package main

import (
	"flag"

	"github.com/golang/glog"
	"github.com/google/trillian-examples/serverless/api"
	"github.com/google/trillian-examples/serverless/internal/log"
	"github.com/google/trillian-examples/serverless/internal/storage/fs"
	"github.com/google/trillian/merkle/rfc6962/hasher"
)

var (
	storageDir = flag.String("storage_dir", "", "Root directory to store log data.")
)

func main() {
	flag.Parse()
	h := hasher.DefaultHasher

	// init storage
	stateRaw, err := fs.ReadLogState(*storageDir)
	if err != nil {
		glog.Exitf("Failed to read log state: %q", err)
	}
	var state api.LogState
	if err := state.UnmarshalText(stateRaw); err != nil {
		glog.Exitf("Failed to unmarshal state: %q", err)
	}
	st, err := fs.Load(*storageDir, &state)
	if err != nil {
		glog.Exitf("Failed to load storage: %q", err)
	}

	// Integrate new entries
	newState, err := log.Integrate(st, h)
	if err != nil {
		glog.Exitf("Failed to integrate: %q", err)
	}

	// Persist new log state.
	newStateRaw, err := newState.MarshalText()
	if err != nil {
		glog.Exitf("Failed to marshal state: %q", err)
	}

	if err := st.WriteLogState(newStateRaw); err != nil {
		glog.Exitf("Failed to store new log state: %q", err)
	}
}
<commit_msg>Exit if nothing to integrate (#318)<commit_after>// Copyright 2021 Google LLC. 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 provides a command line tool for sequencing entries in
// a serverless log.
package main

import (
	"flag"

	"github.com/golang/glog"
	"github.com/google/trillian-examples/serverless/api"
	"github.com/google/trillian-examples/serverless/internal/log"
	"github.com/google/trillian-examples/serverless/internal/storage/fs"
	"github.com/google/trillian/merkle/rfc6962/hasher"
)

var (
	storageDir = flag.String("storage_dir", "", "Root directory to store log data.")
)

func main() {
	flag.Parse()
	h := hasher.DefaultHasher

	// init storage
	stateRaw, err := fs.ReadLogState(*storageDir)
	if err != nil {
		glog.Exitf("Failed to read log state: %q", err)
	}
	var state api.LogState
	if err := state.UnmarshalText(stateRaw); err != nil {
		glog.Exitf("Failed to unmarshal state: %q", err)
	}
	st, err := fs.Load(*storageDir, &state)
	if err != nil {
		glog.Exitf("Failed to load storage: %q", err)
	}

	// Integrate new entries
	newState, err := log.Integrate(st, h)
	if err != nil {
		glog.Exitf("Failed to integrate: %q", err)
	}
	if newState == nil {
		glog.Exit("Nothing to integrate")
	}

	// Persist new log state.
	newStateRaw, err := newState.MarshalText()
	if err != nil {
		glog.Exitf("Failed to marshal state: %q", err)
	}

	if err := st.WriteLogState(newStateRaw); err != nil {
		glog.Exitf("Failed to store new log state: %q", err)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2014 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.

package donna

import ()

var exchangeScores = []int{
	valuePawn.midgame, 	// 2->0
	valueKnight.midgame, 	// 4->1
	valueBishop.midgame, 	// 6->2
	valueRook.midgame, 	// 8->3
	valueQueen.midgame, 	//10->4
	valueQueen.midgame * 8, //12->5
}

func (p *Position) exchangeScore(to, color, score, extra int, board Bitmask) int {
	attackers := p.attackers(to, color, board) & board
	if attackers == 0 {
		return score
	}

	from, best := 0, Checkmate
	for attackers != 0 {
		square := attackers.pop()
		index := p.pieces[square].kind() / 2 - 1
		if exchangeScores[index] < best {
			from = square
			best = exchangeScores[index]
		}
	}

	if best != Checkmate {
		board ^= bit[from]
	}

	return Max(score, -p.exchangeScore(to, color^1, -(score + extra), best, board))
}

func (p *Position) exchange(move Move) int {
	from, to, piece, capture := move.split()

	score, color := 0, move.piece().color()
	if capture != 0 {
		score = exchangeScores[capture.kind() / 2 - 1]
	}
	if promo := move.promo(); promo != 0 {
		score += exchangeScores[promo / 2 - 1] - exchangeScores[0] // Pawn
		piece = promo
	}

	board := p.board ^ bit[from]
	return -p.exchangeScore(to, color^1, -score, exchangeScores[piece.kind() / 2 - 1], board)
}
<commit_msg>Optimized static exchange evaluation<commit_after>// Copyright (c) 2013-2014 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.

package donna

import ()

var exchangeScores = []int{
	0, 0, 						// Zero score for non-capture moves.
	valuePawn.midgame, valuePawn.midgame, 		// Pawn/BlackPawn captures.
	valueKnight.midgame, valueKnight.midgame, 	// Knight/BlackKinght captures.
	valueBishop.midgame, valueBishop.midgame, 	// Bishop/BlackBishop captures.
	valueRook.midgame, valueRook.midgame, 		// Rook/BlackRook captures.
	valueQueen.midgame, valueQueen.midgame, 	// Queen/BlackQueen captures.
	valueQueen.midgame * 8, valueQueen.midgame * 8, // King/BlackKing specials.
}

// Static exchange evaluation.
func (p *Position) exchange(move Move) int {
	from, to, piece, capture := move.split()

	score := exchangeScores[capture]
	if promo := move.promo(); promo != 0 {
		score += exchangeScores[promo] - exchangeScores[Pawn]
		piece = promo
	}

	board := p.board ^ bit[from]
	return -p.exchangeScore(to, piece.color()^1, -score, exchangeScores[piece], board)
}

// Recursive helper method for the static exchange evaluation.
func (p *Position) exchangeScore(to, color, score, extra int, board Bitmask) int {
	attackers := p.attackers(to, color, board) & board
	if attackers == 0 {
		return score
	}

	from, best := 0, Checkmate
	for attackers != 0 {
		square := attackers.pop()
		if index := p.pieces[square]; exchangeScores[index] < best {
			from = square
			best = exchangeScores[index]
		}
	}

	if best != Checkmate {
		board ^= bit[from]
	}

	return Max(score, -p.exchangeScore(to, color^1, -(score + extra), best, board))
}

<|endoftext|>


<commit_before>package cmd_teamfolder

import (
	"bufio"
	"encoding/json"
	"flag"
	"github.com/watermint/toolbox/cmdlet"
	"github.com/watermint/toolbox/dbx_api/dbx_namespace"
	"github.com/watermint/toolbox/dbx_api/dbx_profile"
	"github.com/watermint/toolbox/report"
	"go.uber.org/zap"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

type CmdTeamTeamFolderSize struct {
	*cmdlet.SimpleCommandlet
	optDepth     int
	optCachePath string
	report       report.Factory
}

func (CmdTeamTeamFolderSize) Name() string {
	return "size"
}

func (CmdTeamTeamFolderSize) Desc() string {
	return "Calculate size of team folder"
}

func (CmdTeamTeamFolderSize) Usage() string {
	return ""
}

func (z *CmdTeamTeamFolderSize) FlagConfig(f *flag.FlagSet) {
	z.report.FlagConfig(f)

	descOptDepth := "Depth directories deep"
	f.IntVar(&z.optDepth, "depth", 2, descOptDepth)

	descUseCached := "Use cached information, or create cache if not exist"
	f.StringVar(&z.optCachePath, "cache", "", descUseCached)
}

func (z *CmdTeamTeamFolderSize) Exec(args []string) {
	z.report.Init(z.Log())
	defer z.report.Close()

	nsz := &NamespaceSizes{}
	nsz.Init()
	if z.optCachePath != "" && z.isCacheFilesAvailable() {
		z.Log().Info("Calculating size from cache")
		z.loadFromCache(nsz)
	} else {
		z.Log().Info("Retrieve data from API, then calculating size")
		z.loadFromApi(nsz)
	}

	z.Log().Info("Reporting result")
	for _, sz := range nsz.Sizes {
		z.report.Report(sz)
	}
}

func (z *CmdTeamTeamFolderSize) loadFromCache(nsz *NamespaceSizes) {
	if f, err := os.Open(z.cachePathFile()); err != nil {
		r := bufio.NewReader(f)
		for {
			line, _, err := r.ReadLine()
			if err != nil {
				z.Log().Warn(
					"Unable to read file",
					zap.String("file", z.cachePathFile()),
					zap.Error(err),
				)
				break
			}

			nsf := &dbx_namespace.NamespaceFile{}
			if err = json.Unmarshal(line, nsf); err != nil {
				z.Log().Warn(
					"Unable to parse line",
					zap.String("file", z.cachePathFile()),
					zap.String("line", string(line)),
					zap.Error(err),
				)
				break
			}

			nsz.OnFile(nsf)
		}
		f.Close()
	}

	if f, err := os.Open(z.cachePathFolder()); err != nil {
		r := bufio.NewReader(f)
		for {
			line, _, err := r.ReadLine()
			if err != nil {
				z.Log().Warn(
					"Unable to read file",
					zap.String("file", z.cachePathFolder()),
					zap.Error(err),
				)
				break
			}

			nsf := &dbx_namespace.NamespaceFolder{}
			if err = json.Unmarshal(line, nsf); err != nil {
				z.Log().Warn(
					"Unable to parse line",
					zap.String("file", z.cachePathFolder()),
					zap.String("line", string(line)),
					zap.Error(err),
				)
				break
			}

			nsz.OnFolder(nsf)
		}
		f.Close()
	}

}

func (z *CmdTeamTeamFolderSize) loadFromApi(nsz *NamespaceSizes) {
	apiFile, err := z.ExecContext.LoadOrAuthBusinessFile()
	if err != nil {
		return
	}

	admin, ea, _ := dbx_profile.AuthenticatedAdmin(apiFile)
	if ea.IsFailure() {
		z.DefaultErrorHandler(ea)
		return
	}
	cacheWriter := report.Factory{}
	cacheWriter.ReportPath = z.optCachePath
	cacheWriter.ReportFormat = "json"
	cacheWriter.DefaultWriter = ioutil.Discard
	cacheWriter.Init(z.Log())

	namespaceFile := dbx_namespace.ListNamespaceFile{}
	namespaceFile.AsAdminId = admin.TeamMemberId
	namespaceFile.OnError = z.DefaultErrorHandler
	namespaceFile.OnNamespace = func(namespace *dbx_namespace.Namespace) bool {
		if namespace.NamespaceType != "team_folder" {
			z.Log().Debug(
				"Skip non `team_folder` namespace",
				zap.String("namespace_type", namespace.NamespaceType),
				zap.String("namespace_id", namespace.NamespaceId),
				zap.String("name", namespace.Name),
			)
			return false
		}
		z.Log().Info("Scanning folder",
			zap.String("namespace_type", namespace.NamespaceType),
			zap.String("namespace_id", namespace.NamespaceId),
			zap.String("name", namespace.Name),
		)
		return true
	}
	namespaceFile.OnFolder = func(folder *dbx_namespace.NamespaceFolder) bool {
		nsz.OnFolder(folder)
		cacheWriter.Report(folder)
		return true
	}
	namespaceFile.OnFile = func(file *dbx_namespace.NamespaceFile) bool {
		nsz.OnFile(file)
		cacheWriter.Report(file)
		return true
	}
	namespaceFile.OnDelete = func(deleted *dbx_namespace.NamespaceDeleted) bool {
		nsz.OnDelete(deleted)
		cacheWriter.Report(deleted)
		return true
	}
	namespaceFile.List(apiFile)
}

func (z *CmdTeamTeamFolderSize) cachePathFile() string {
	return filepath.Join(z.optCachePath, "NamespaceFile.json")
}
func (z *CmdTeamTeamFolderSize) cachePathFolder() string {
	return filepath.Join(z.optCachePath, "NamespaceFolder.json")
}

func (z *CmdTeamTeamFolderSize) isCacheFilesAvailable() bool {
	avail := false
	if _, err := os.Stat(z.cachePathFile()); !os.IsNotExist(err) {
		avail = true
	}
	if _, err := os.Stat(z.cachePathFolder()); !os.IsNotExist(err) {
		avail = true
	}
	return avail
}

type NamespaceSize struct {
	Namespace       *dbx_namespace.Namespace `json:"namespace"`
	Path            string                   `json:"path"`
	FileCount       int64                    `json:"file_count"`
	FolderCount     int64                    `json:"folder_count"`
	DescendantCount int64                    `json:"descendant_count"`
	Size            int64                    `json:"size"`
}

type NamespaceSizes struct {
	Sizes map[string]*NamespaceSize
	Depth int
}

func (z *NamespaceSizes) Init() {
	z.Sizes = make(map[string]*NamespaceSize)
}

func (z *NamespaceSizes) parent(path string) string {
	pe := strings.Split(path, "/")
	le := len(pe)
	if le <= 2 {
		return pe[0] + "/"
	}
	return strings.Join(pe[:le-1], "/")
}

func (z *NamespaceSizes) increment(namespace *dbx_namespace.Namespace, path string, folder, file, size int64) {
	if sz, ok := z.Sizes[path]; ok {
		sz.DescendantCount += folder + file
		sz.FolderCount += folder
		sz.FileCount += file
		sz.Size += size
	} else {
		sz = &NamespaceSize{
			Namespace:       namespace,
			Path:            path,
			DescendantCount: folder + file,
			FolderCount:     folder,
			FileCount:       file,
			Size:            size,
		}
		z.Sizes[path] = sz
	}

	pp := z.parent(path)
	if pp != path && path != "/" {
		z.increment(namespace, pp, folder, file, size)
	}
}

func (z *NamespaceSizes) Dir(path string) string {
	pathElems := strings.Split(path, "/")
	if len(pathElems) <= 1 {
		return "/"
	} else {
		pathElems = pathElems[:len(pathElems)-1]
		return strings.Join(pathElems, "/")
	}
}

func (z *NamespaceSizes) Path(namespace *dbx_namespace.Namespace, path string) string {
	pathElems := strings.Split(path, "/")
	dp := ""
	if len(pathElems) >= z.Depth+1 {
		dp = strings.Join(pathElems[:z.Depth+1], "/")
	} else {
		dp = strings.Join(pathElems, "/")
	}
	if dp == "" {
		return namespace.NamespaceId + "/"
	}

	return namespace.NamespaceId + dp
}

func (z *NamespaceSizes) OnFolder(folder *dbx_namespace.NamespaceFolder) bool {
	z.increment(folder.Namespace, z.Path(folder.Namespace, z.Dir(folder.Folder.PathLower)), 1, 0, 0)
	return true
}

func (z *NamespaceSizes) OnFile(file *dbx_namespace.NamespaceFile) bool {
	z.increment(file.Namespace, z.Path(file.Namespace, z.Dir(file.File.PathLower)), 0, 1, file.File.Size)
	return true
}

func (z *NamespaceSizes) OnDelete(deleted *dbx_namespace.NamespaceDeleted) bool {
	// nop
	return true
}
<commit_msg>fix team folder size<commit_after>package cmd_teamfolder

import (
	"bufio"
	"encoding/json"
	"flag"
	"github.com/watermint/toolbox/cmdlet"
	"github.com/watermint/toolbox/dbx_api/dbx_namespace"
	"github.com/watermint/toolbox/dbx_api/dbx_profile"
	"github.com/watermint/toolbox/report"
	"go.uber.org/zap"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

type CmdTeamTeamFolderSize struct {
	*cmdlet.SimpleCommandlet
	optDepth     int
	optCachePath string
	report       report.Factory
}

func (CmdTeamTeamFolderSize) Name() string {
	return "size"
}

func (CmdTeamTeamFolderSize) Desc() string {
	return "Calculate size of team folder"
}

func (CmdTeamTeamFolderSize) Usage() string {
	return ""
}

func (z *CmdTeamTeamFolderSize) FlagConfig(f *flag.FlagSet) {
	z.report.FlagConfig(f)

	descOptDepth := "Depth directories deep"
	f.IntVar(&z.optDepth, "depth", 2, descOptDepth)

	descUseCached := "Use cached information, or create cache if not exist"
	f.StringVar(&z.optCachePath, "cache", "", descUseCached)
}

func (z *CmdTeamTeamFolderSize) Exec(args []string) {
	z.report.Init(z.Log())
	defer z.report.Close()

	nsz := &NamespaceSizes{}
	nsz.Init()
	if z.optCachePath != "" && z.isCacheFilesAvailable() {
		z.Log().Info("Calculating size from cache")
		z.loadFromCache(nsz)
	} else {
		z.Log().Info("Retrieve data from API, then calculating size")
		z.loadFromApi(nsz)
	}

	z.Log().Info("Reporting result")
	for _, sz := range nsz.Sizes {
		z.report.Report(sz)
	}
}

func (z *CmdTeamTeamFolderSize) loadFromCache(nsz *NamespaceSizes) {
	if f, err := os.Open(z.cachePathFile()); err != nil {
		r := bufio.NewReader(f)
		for {
			line, _, err := r.ReadLine()
			if err != nil {
				z.Log().Warn(
					"Unable to read file",
					zap.String("file", z.cachePathFile()),
					zap.Error(err),
				)
				break
			}

			nsf := &dbx_namespace.NamespaceFile{}
			if err = json.Unmarshal(line, nsf); err != nil {
				z.Log().Warn(
					"Unable to parse line",
					zap.String("file", z.cachePathFile()),
					zap.String("line", string(line)),
					zap.Error(err),
				)
				break
			}

			nsz.OnFile(nsf)
		}
		f.Close()
	}

	if f, err := os.Open(z.cachePathFolder()); err != nil {
		r := bufio.NewReader(f)
		for {
			line, _, err := r.ReadLine()
			if err != nil {
				z.Log().Warn(
					"Unable to read file",
					zap.String("file", z.cachePathFolder()),
					zap.Error(err),
				)
				break
			}

			nsf := &dbx_namespace.NamespaceFolder{}
			if err = json.Unmarshal(line, nsf); err != nil {
				z.Log().Warn(
					"Unable to parse line",
					zap.String("file", z.cachePathFolder()),
					zap.String("line", string(line)),
					zap.Error(err),
				)
				break
			}

			nsz.OnFolder(nsf)
		}
		f.Close()
	}

}

func (z *CmdTeamTeamFolderSize) loadFromApi(nsz *NamespaceSizes) {
	apiFile, err := z.ExecContext.LoadOrAuthBusinessFile()
	if err != nil {
		return
	}

	admin, ea, _ := dbx_profile.AuthenticatedAdmin(apiFile)
	if ea.IsFailure() {
		z.DefaultErrorHandler(ea)
		return
	}
	cacheWriter := report.Factory{}
	cacheWriter.ReportPath = z.optCachePath
	cacheWriter.ReportFormat = "json"
	cacheWriter.DefaultWriter = ioutil.Discard
	cacheWriter.Init(z.Log())

	namespaceFile := dbx_namespace.ListNamespaceFile{}
	namespaceFile.AsAdminId = admin.TeamMemberId
	namespaceFile.OptIncludeTeamFolder = true
	namespaceFile.OnError = z.DefaultErrorHandler
	namespaceFile.OnNamespace = func(namespace *dbx_namespace.Namespace) bool {
		z.Log().Info("Scanning folder",
			zap.String("namespace_type", namespace.NamespaceType),
			zap.String("namespace_id", namespace.NamespaceId),
			zap.String("name", namespace.Name),
		)
		return true
	}
	namespaceFile.OnFolder = func(folder *dbx_namespace.NamespaceFolder) bool {
		nsz.OnFolder(folder)
		cacheWriter.Report(folder)
		return true
	}
	namespaceFile.OnFile = func(file *dbx_namespace.NamespaceFile) bool {
		nsz.OnFile(file)
		cacheWriter.Report(file)
		return true
	}
	namespaceFile.OnDelete = func(deleted *dbx_namespace.NamespaceDeleted) bool {
		nsz.OnDelete(deleted)
		cacheWriter.Report(deleted)
		return true
	}
	namespaceFile.List(apiFile)
}

func (z *CmdTeamTeamFolderSize) cachePathFile() string {
	return filepath.Join(z.optCachePath, "NamespaceFile.json")
}
func (z *CmdTeamTeamFolderSize) cachePathFolder() string {
	return filepath.Join(z.optCachePath, "NamespaceFolder.json")
}

func (z *CmdTeamTeamFolderSize) isCacheFilesAvailable() bool {
	avail := false
	if _, err := os.Stat(z.cachePathFile()); !os.IsNotExist(err) {
		avail = true
	}
	if _, err := os.Stat(z.cachePathFolder()); !os.IsNotExist(err) {
		avail = true
	}
	return avail
}

type NamespaceSize struct {
	Namespace       *dbx_namespace.Namespace `json:"namespace"`
	Path            string                   `json:"path"`
	FileCount       int64                    `json:"file_count"`
	FolderCount     int64                    `json:"folder_count"`
	DescendantCount int64                    `json:"descendant_count"`
	Size            int64                    `json:"size"`
}

type NamespaceSizes struct {
	Sizes map[string]*NamespaceSize
	Depth int
}

func (z *NamespaceSizes) Init() {
	z.Sizes = make(map[string]*NamespaceSize)
}

func (z *NamespaceSizes) parent(path string) string {
	pe := strings.Split(path, "/")
	le := len(pe)
	if le <= 2 {
		return pe[0] + "/"
	}
	return strings.Join(pe[:le-1], "/")
}

func (z *NamespaceSizes) increment(namespace *dbx_namespace.Namespace, path string, folder, file, size int64) {
	if sz, ok := z.Sizes[path]; ok {
		sz.DescendantCount += folder + file
		sz.FolderCount += folder
		sz.FileCount += file
		sz.Size += size
	} else {
		sz = &NamespaceSize{
			Namespace:       namespace,
			Path:            path,
			DescendantCount: folder + file,
			FolderCount:     folder,
			FileCount:       file,
			Size:            size,
		}
		z.Sizes[path] = sz
	}

	pp := z.parent(path)
	if pp != path && path != "/" {
		z.increment(namespace, pp, folder, file, size)
	}
}

func (z *NamespaceSizes) Dir(path string) string {
	pathElems := strings.Split(path, "/")
	if len(pathElems) <= 1 {
		return "/"
	} else {
		pathElems = pathElems[:len(pathElems)-1]
		return strings.Join(pathElems, "/")
	}
}

func (z *NamespaceSizes) Path(namespace *dbx_namespace.Namespace, path string) string {
	pathElems := strings.Split(path, "/")
	dp := ""
	if len(pathElems) >= z.Depth+1 {
		dp = strings.Join(pathElems[:z.Depth+1], "/")
	} else {
		dp = strings.Join(pathElems, "/")
	}
	if dp == "" {
		return namespace.NamespaceId + "/"
	}

	return namespace.NamespaceId + dp
}

func (z *NamespaceSizes) OnFolder(folder *dbx_namespace.NamespaceFolder) bool {
	z.increment(folder.Namespace, z.Path(folder.Namespace, z.Dir(folder.Folder.PathLower)), 1, 0, 0)
	return true
}

func (z *NamespaceSizes) OnFile(file *dbx_namespace.NamespaceFile) bool {
	z.increment(file.Namespace, z.Path(file.Namespace, z.Dir(file.File.PathLower)), 0, 1, file.File.Size)
	return true
}

func (z *NamespaceSizes) OnDelete(deleted *dbx_namespace.NamespaceDeleted) bool {
	// nop
	return true
}
<|endoftext|>


<commit_before>package state_test

import (
	"fmt"
	"labix.org/v2/mgo/bson"
	. "launchpad.net/gocheck"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/version"
)

type tooler interface {
	AgentTools() (*state.Tools, error)
	SetAgentTools(t *state.Tools) error
	EnsureDying() error
	EnsureDead() error
	Life() state.Life
	Refresh() error
}

var _ = Suite(&ToolsSuite{})

type ToolsSuite struct {
	ConnSuite
}

func newTools(vers, url string) *state.Tools {
	return &state.Tools{
		Binary: version.MustParseBinary(vers),
		URL:    url,
	}
}

func testAgentTools(c *C, obj tooler, agent string) {
	// object starts with zero'd tools.
	t, err := obj.AgentTools()
	c.Assert(err, IsNil)
	c.Assert(t, DeepEquals, &state.Tools{})

	err = obj.SetAgentTools(&state.Tools{})
	c.Assert(err, ErrorMatches, fmt.Sprintf("cannot set agent tools for %s: empty series or arch", agent))
	t2 := newTools("7.8.9-foo-bar", "http://arble.tgz")
	err = obj.SetAgentTools(t2)
	c.Assert(err, IsNil)
	t3, err := obj.AgentTools()
	c.Assert(err, IsNil)
	c.Assert(t3, DeepEquals, t2)
	err = obj.Refresh()
	c.Assert(err, IsNil)
	t3, err = obj.AgentTools()
	c.Assert(err, IsNil)
	c.Assert(t3, DeepEquals, t2)

	testWhenDying(c, obj, noErr, notAliveErr, func() error {
		return obj.SetAgentTools(t2)
	})
}

func (s *ToolsSuite) TestMachineAgentTools(c *C) {
	m, err := s.State.AddMachine()
	c.Assert(err, IsNil)
	testAgentTools(c, m, "machine 0")
}

func (s *ToolsSuite) TestUnitAgentTools(c *C) {
	charm := s.AddTestingCharm(c, "dummy")
	svc, err := s.State.AddService("wordpress", charm)
	c.Assert(err, IsNil)
	unit, err := svc.AddUnit()
	c.Assert(err, IsNil)
	testAgentTools(c, unit, `unit "wordpress/0"`)
}

func (s *ToolsSuite) TestMarshalUnmarshal(c *C) {
	tools := newTools("7.8.9-foo-bar", "http://arble.tgz")
	data, err := bson.Marshal(&tools)
	c.Assert(err, IsNil)

	// Check the exact document.
	want := bson.M{
		"version": tools.Binary.String(),
		"url":     tools.URL,
	}
	got := bson.M{}
	err = bson.Unmarshal(data, &got)
	c.Assert(err, IsNil)
	c.Assert(got, DeepEquals, want)

	// Check that it unpacks properly too.
	var t state.Tools
	err = bson.Unmarshal(data, &t)
	c.Assert(err, IsNil)
	c.Assert(t, Equals, *tools)
}

func (s *ToolsSuite) TestUnmarshalNilRoundtrip(c *C) {
	// We have a custom unmarshaller that should keep
	// the field unset when it finds a nil value.
	var v struct { Tools *state.Tools }
	data, err := bson.Marshal(&v)
	c.Assert(err, IsNil)
	err = bson.Unmarshal(data, &v)
	c.Assert(err, IsNil)
	c.Assert(v.Tools, IsNil)
}
<commit_msg>gofmt<commit_after>package state_test

import (
	"fmt"
	"labix.org/v2/mgo/bson"
	. "launchpad.net/gocheck"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/version"
)

type tooler interface {
	AgentTools() (*state.Tools, error)
	SetAgentTools(t *state.Tools) error
	EnsureDying() error
	EnsureDead() error
	Life() state.Life
	Refresh() error
}

var _ = Suite(&ToolsSuite{})

type ToolsSuite struct {
	ConnSuite
}

func newTools(vers, url string) *state.Tools {
	return &state.Tools{
		Binary: version.MustParseBinary(vers),
		URL:    url,
	}
}

func testAgentTools(c *C, obj tooler, agent string) {
	// object starts with zero'd tools.
	t, err := obj.AgentTools()
	c.Assert(err, IsNil)
	c.Assert(t, DeepEquals, &state.Tools{})

	err = obj.SetAgentTools(&state.Tools{})
	c.Assert(err, ErrorMatches, fmt.Sprintf("cannot set agent tools for %s: empty series or arch", agent))
	t2 := newTools("7.8.9-foo-bar", "http://arble.tgz")
	err = obj.SetAgentTools(t2)
	c.Assert(err, IsNil)
	t3, err := obj.AgentTools()
	c.Assert(err, IsNil)
	c.Assert(t3, DeepEquals, t2)
	err = obj.Refresh()
	c.Assert(err, IsNil)
	t3, err = obj.AgentTools()
	c.Assert(err, IsNil)
	c.Assert(t3, DeepEquals, t2)

	testWhenDying(c, obj, noErr, notAliveErr, func() error {
		return obj.SetAgentTools(t2)
	})
}

func (s *ToolsSuite) TestMachineAgentTools(c *C) {
	m, err := s.State.AddMachine()
	c.Assert(err, IsNil)
	testAgentTools(c, m, "machine 0")
}

func (s *ToolsSuite) TestUnitAgentTools(c *C) {
	charm := s.AddTestingCharm(c, "dummy")
	svc, err := s.State.AddService("wordpress", charm)
	c.Assert(err, IsNil)
	unit, err := svc.AddUnit()
	c.Assert(err, IsNil)
	testAgentTools(c, unit, `unit "wordpress/0"`)
}

func (s *ToolsSuite) TestMarshalUnmarshal(c *C) {
	tools := newTools("7.8.9-foo-bar", "http://arble.tgz")
	data, err := bson.Marshal(&tools)
	c.Assert(err, IsNil)

	// Check the exact document.
	want := bson.M{
		"version": tools.Binary.String(),
		"url":     tools.URL,
	}
	got := bson.M{}
	err = bson.Unmarshal(data, &got)
	c.Assert(err, IsNil)
	c.Assert(got, DeepEquals, want)

	// Check that it unpacks properly too.
	var t state.Tools
	err = bson.Unmarshal(data, &t)
	c.Assert(err, IsNil)
	c.Assert(t, Equals, *tools)
}

func (s *ToolsSuite) TestUnmarshalNilRoundtrip(c *C) {
	// We have a custom unmarshaller that should keep
	// the field unset when it finds a nil value.
	var v struct{ Tools *state.Tools }
	data, err := bson.Marshal(&v)
	c.Assert(err, IsNil)
	err = bson.Unmarshal(data, &v)
	c.Assert(err, IsNil)
	c.Assert(v.Tools, IsNil)
}
<|endoftext|>


<commit_before>package main

import "honnef.co/go/js/dom"

func settingsTab(c dom.Element) {

}
<commit_msg>Implemented server settings change<commit_after>package main

import (
	"github.com/MJKWoolnough/gopherjs/xdom"
	"github.com/MJKWoolnough/gopherjs/xform"
	"github.com/MJKWoolnough/gopherjs/xjs"
	"honnef.co/go/js/dom"
)

func settingsTab(c dom.Element) {
	s, err := RPC.Settings()
	if err != nil {
		xjs.Alert("Error reading settings: %s", err)
		return
	}
	c.AppendChild(xjs.SetInnerText(xdom.H2(), "Change Settings"))
	c.AppendChild(xform.Label("Server Name", "serverName"))
	sn := xform.InputText("serverName", s.ServerName)
	c.AppendChild(sn)
	c.AppendChild(xdom.Br())
	c.AppendChild(xform.Label("Listen Address", "listenAddr"))
	la := xform.InputText("listenAddr", s.ListenAddr)
	c.AppendChild(la)
	c.AppendChild(xdom.Br())
	c.AppendChild(xform.Label("Servers Path", "serversPath"))
	sp := xform.InputText("serversPath", s.DirServers)
	c.AppendChild(sp)
	c.AppendChild(xdom.Br())
	c.AppendChild(xform.Label("Maps Path", "mapsPath"))
	mp := xform.InputText("mapsPath", s.DirMaps)
	c.AppendChild(mp)
	c.AppendChild(xdom.Br())

	sb := xdom.Button()
	xjs.SetInnerText(sb, "Save")
	sb.AddEventListener("click", false, func(dom.Event) {
		go func() {
			s.ServerName = sn.Value
			s.ListenAddr = la.Value
			s.DirServers = sp.Value
			s.DirMaps = mp.Value
			if err := RPC.SetSettings(s); err != nil {
				xjs.Alert("Error saving settings: %s", err)
			} else {
				SetTitle(sn.Value)
			}
		}()
	})
	c.AppendChild(sb)
}
<|endoftext|>


<commit_before>package resource

import (
	"fmt"
	"os"
	"sync/atomic"
	"testing"

	"github.com/hashicorp/terraform/terraform"
)

func init() {
	testTesting = true

	if err := os.Setenv(TestEnvVar, "1"); err != nil {
		panic(err)
	}
}

func TestTest(t *testing.T) {
	mp := testProvider()
	mp.DiffReturn = nil

	mp.ApplyReturn = &terraform.InstanceState{
		ID: "foo",
	}
	var refreshCount int32
	mp.RefreshFn = func(*terraform.InstanceInfo, *terraform.InstanceState) (*terraform.InstanceState, error) {
		atomic.AddInt32(&refreshCount, 1)
		if atomic.LoadInt32(&refreshCount) == 1 {
			return &terraform.InstanceState{ID: "foo"}, nil
		} else {
			return nil, nil
		}
	}

	checkDestroy := false
	checkStep := false

	checkDestroyFn := func(*terraform.State) error {
		checkDestroy = true
		return nil
	}

	checkStepFn := func(s *terraform.State) error {
		checkStep = true

		rs, ok := s.RootModule().Resources["test_instance.foo"]
		if !ok {
			t.Error("test_instance.foo is not present")
			return nil
		}
		is := rs.Primary
		if is.ID != "foo" {
			t.Errorf("bad check ID: %s", is.ID)
		}

		return nil
	}

	mt := new(mockT)
	Test(mt, TestCase{
		Providers: map[string]terraform.ResourceProvider{
			"test": mp,
		},
		CheckDestroy: checkDestroyFn,
		Steps: []TestStep{
			TestStep{
				Config: testConfigStr,
				Check:  checkStepFn,
			},
		},
	})

	if mt.failed() {
		t.Fatalf("test failed: %s", mt.failMessage())
	}
	if !checkStep {
		t.Fatal("didn't call check for step")
	}
	if !checkDestroy {
		t.Fatal("didn't call check for destroy")
	}
}

func TestTest_idRefresh(t *testing.T) {
	// Refresh count should be 3:
	//   1.) initial Ref/Plan/Apply
	//   2.) post Ref/Plan/Apply for plan-check
	//   3.) id refresh check
	var expectedRefresh int32 = 3

	mp := testProvider()
	mp.DiffReturn = nil

	mp.ApplyReturn = &terraform.InstanceState{
		ID: "foo",
	}
	var refreshCount int32
	mp.RefreshFn = func(*terraform.InstanceInfo, *terraform.InstanceState) (*terraform.InstanceState, error) {
		atomic.AddInt32(&refreshCount, 1)
		if atomic.LoadInt32(&refreshCount) < expectedRefresh {
			return &terraform.InstanceState{ID: "foo"}, nil
		} else {
			return nil, nil
		}
	}

	mt := new(mockT)
	Test(mt, TestCase{
		Providers: map[string]terraform.ResourceProvider{
			"test": mp,
		},
		Steps: []TestStep{
			TestStep{
				Config: testConfigStr,
			},
		},
	})

	if mt.failed() {
		t.Fatalf("test failed: %s", mt.failMessage())
	}

	// See declaration of expectedRefresh for why that number
	if refreshCount != expectedRefresh {
		t.Fatalf("bad refresh count: %d", refreshCount)
	}
}

func TestTest_idRefreshFail(t *testing.T) {
	// Refresh count should be 3:
	//   1.) initial Ref/Plan/Apply
	//   2.) post Ref/Plan/Apply for plan-check
	//   3.) id refresh check
	var expectedRefresh int32 = 3

	mp := testProvider()
	mp.DiffReturn = nil

	mp.ApplyReturn = &terraform.InstanceState{
		ID: "foo",
	}
	var refreshCount int32
	mp.RefreshFn = func(*terraform.InstanceInfo, *terraform.InstanceState) (*terraform.InstanceState, error) {
		atomic.AddInt32(&refreshCount, 1)
		if atomic.LoadInt32(&refreshCount) == expectedRefresh-1 {
			return &terraform.InstanceState{
				ID:         "foo",
				Attributes: map[string]string{"foo": "bar"},
			}, nil
		} else if atomic.LoadInt32(&refreshCount) < expectedRefresh {
			return &terraform.InstanceState{ID: "foo"}, nil
		} else {
			return nil, nil
		}
	}

	mt := new(mockT)
	Test(mt, TestCase{
		Providers: map[string]terraform.ResourceProvider{
			"test": mp,
		},
		Steps: []TestStep{
			TestStep{
				Config: testConfigStr,
			},
		},
	})

	if !mt.failed() {
		t.Fatal("test didn't fail")
	}

	// See declaration of expectedRefresh for why that number
	if refreshCount != expectedRefresh {
		t.Fatalf("bad refresh count: %d", refreshCount)
	}
}

func TestTest_empty(t *testing.T) {
	destroyCalled := false
	checkDestroyFn := func(*terraform.State) error {
		destroyCalled = true
		return nil
	}

	mt := new(mockT)
	Test(mt, TestCase{
		CheckDestroy: checkDestroyFn,
	})

	if mt.failed() {
		t.Fatal("test failed")
	}
	if destroyCalled {
		t.Fatal("should not call check destroy if there is no steps")
	}
}

func TestTest_noEnv(t *testing.T) {
	// Unset the variable
	if err := os.Setenv(TestEnvVar, ""); err != nil {
		t.Fatalf("err: %s", err)
	}
	defer os.Setenv(TestEnvVar, "1")

	mt := new(mockT)
	Test(mt, TestCase{})

	if !mt.SkipCalled {
		t.Fatal("skip not called")
	}
}

func TestTest_preCheck(t *testing.T) {
	called := false

	mt := new(mockT)
	Test(mt, TestCase{
		PreCheck: func() { called = true },
	})

	if !called {
		t.Fatal("precheck should be called")
	}
}

func TestTest_stepError(t *testing.T) {
	mp := testProvider()
	mp.ApplyReturn = &terraform.InstanceState{
		ID: "foo",
	}

	checkDestroy := false

	checkDestroyFn := func(*terraform.State) error {
		checkDestroy = true
		return nil
	}

	checkStepFn := func(*terraform.State) error {
		return fmt.Errorf("error")
	}

	mt := new(mockT)
	Test(mt, TestCase{
		Providers: map[string]terraform.ResourceProvider{
			"test": mp,
		},
		CheckDestroy: checkDestroyFn,
		Steps: []TestStep{
			TestStep{
				Config: testConfigStr,
				Check:  checkStepFn,
			},
		},
	})

	if !mt.failed() {
		t.Fatal("test should've failed")
	}
	expected := "Step 0 error: Check failed: error"
	if mt.failMessage() != expected {
		t.Fatalf("Expected message: %s\n\ngot:\n\n%s", expected, mt.failMessage())
	}

	if !checkDestroy {
		t.Fatal("didn't call check for destroy")
	}
}

func TestComposeTestCheckFunc(t *testing.T) {
	cases := []struct {
		F      []TestCheckFunc
		Result string
	}{
		{
			F: []TestCheckFunc{
				func(*terraform.State) error { return nil },
			},
			Result: "",
		},

		{
			F: []TestCheckFunc{
				func(*terraform.State) error {
					return fmt.Errorf("error")
				},
				func(*terraform.State) error { return nil },
			},
			Result: "Check 1/2 error: error",
		},

		{
			F: []TestCheckFunc{
				func(*terraform.State) error { return nil },
				func(*terraform.State) error {
					return fmt.Errorf("error")
				},
			},
			Result: "Check 2/2 error: error",
		},

		{
			F: []TestCheckFunc{
				func(*terraform.State) error { return nil },
				func(*terraform.State) error { return nil },
			},
			Result: "",
		},
	}

	for i, tc := range cases {
		f := ComposeTestCheckFunc(tc.F...)
		err := f(nil)
		if err == nil {
			err = fmt.Errorf("")
		}
		if tc.Result != err.Error() {
			t.Fatalf("Case %d bad: %s", i, err)
		}
	}
}

// mockT implements TestT for testing
type mockT struct {
	ErrorCalled bool
	ErrorArgs   []interface{}
	FatalCalled bool
	FatalArgs   []interface{}
	SkipCalled  bool
	SkipArgs    []interface{}

	f bool
}

func (t *mockT) Error(args ...interface{}) {
	t.ErrorCalled = true
	t.ErrorArgs = args
	t.f = true
}

func (t *mockT) Fatal(args ...interface{}) {
	t.FatalCalled = true
	t.FatalArgs = args
	t.f = true
}

func (t *mockT) Skip(args ...interface{}) {
	t.SkipCalled = true
	t.SkipArgs = args
	t.f = true
}

func (t *mockT) failed() bool {
	return t.f
}

func (t *mockT) failMessage() string {
	if t.FatalCalled {
		return t.FatalArgs[0].(string)
	} else if t.ErrorCalled {
		return t.ErrorArgs[0].(string)
	} else if t.SkipCalled {
		return t.SkipArgs[0].(string)
	}

	return "unknown"
}

func testProvider() *terraform.MockResourceProvider {
	mp := new(terraform.MockResourceProvider)
	mp.DiffReturn = &terraform.InstanceDiff{
		Attributes: map[string]*terraform.ResourceAttrDiff{
			"foo": &terraform.ResourceAttrDiff{
				New: "bar",
			},
		},
	}
	mp.ResourcesReturn = []terraform.ResourceType{
		terraform.ResourceType{Name: "test_instance"},
	}

	return mp
}

const testConfigStr = `
resource "test_instance" "foo" {}
`
<commit_msg>helper/resource: fix tests<commit_after>package resource

import (
	"fmt"
	"os"
	"sync/atomic"
	"testing"

	"github.com/hashicorp/terraform/terraform"
)

func init() {
	testTesting = true

	// TODO: Remove when we remove the guard on id checks
	if err := os.Setenv("TF_ACC_IDONLY", "1"); err != nil {
		panic(err)
	}

	if err := os.Setenv(TestEnvVar, "1"); err != nil {
		panic(err)
	}
}

func TestTest(t *testing.T) {
	mp := testProvider()
	mp.DiffReturn = nil

	mp.ApplyFn = func(
		info *terraform.InstanceInfo,
		state *terraform.InstanceState,
		diff *terraform.InstanceDiff) (*terraform.InstanceState, error) {
		if !diff.Destroy {
			return &terraform.InstanceState{
				ID: "foo",
			}, nil
		}

		return nil, nil
	}

	var refreshCount int32
	mp.RefreshFn = func(*terraform.InstanceInfo, *terraform.InstanceState) (*terraform.InstanceState, error) {
		atomic.AddInt32(&refreshCount, 1)
		return &terraform.InstanceState{ID: "foo"}, nil
	}

	checkDestroy := false
	checkStep := false

	checkDestroyFn := func(*terraform.State) error {
		checkDestroy = true
		return nil
	}

	checkStepFn := func(s *terraform.State) error {
		checkStep = true

		rs, ok := s.RootModule().Resources["test_instance.foo"]
		if !ok {
			t.Error("test_instance.foo is not present")
			return nil
		}
		is := rs.Primary
		if is.ID != "foo" {
			t.Errorf("bad check ID: %s", is.ID)
		}

		return nil
	}

	mt := new(mockT)
	Test(mt, TestCase{
		Providers: map[string]terraform.ResourceProvider{
			"test": mp,
		},
		CheckDestroy: checkDestroyFn,
		Steps: []TestStep{
			TestStep{
				Config: testConfigStr,
				Check:  checkStepFn,
			},
		},
	})

	if mt.failed() {
		t.Fatalf("test failed: %s", mt.failMessage())
	}
	if !checkStep {
		t.Fatal("didn't call check for step")
	}
	if !checkDestroy {
		t.Fatal("didn't call check for destroy")
	}
}

func TestTest_idRefresh(t *testing.T) {
	// Refresh count should be 3:
	//   1.) initial Ref/Plan/Apply
	//   2.) post Ref/Plan/Apply for plan-check
	//   3.) id refresh check
	var expectedRefresh int32 = 3

	mp := testProvider()
	mp.DiffReturn = nil

	mp.ApplyFn = func(
		info *terraform.InstanceInfo,
		state *terraform.InstanceState,
		diff *terraform.InstanceDiff) (*terraform.InstanceState, error) {
		if !diff.Destroy {
			return &terraform.InstanceState{
				ID: "foo",
			}, nil
		}

		return nil, nil
	}

	var refreshCount int32
	mp.RefreshFn = func(*terraform.InstanceInfo, *terraform.InstanceState) (*terraform.InstanceState, error) {
		atomic.AddInt32(&refreshCount, 1)
		return &terraform.InstanceState{ID: "foo"}, nil
	}

	mt := new(mockT)
	Test(mt, TestCase{
		Providers: map[string]terraform.ResourceProvider{
			"test": mp,
		},
		Steps: []TestStep{
			TestStep{
				Config: testConfigStr,
			},
		},
	})

	if mt.failed() {
		t.Fatalf("test failed: %s", mt.failMessage())
	}

	// See declaration of expectedRefresh for why that number
	if refreshCount != expectedRefresh {
		t.Fatalf("bad refresh count: %d", refreshCount)
	}
}

func TestTest_idRefreshFail(t *testing.T) {
	// Refresh count should be 3:
	//   1.) initial Ref/Plan/Apply
	//   2.) post Ref/Plan/Apply for plan-check
	//   3.) id refresh check
	var expectedRefresh int32 = 3

	mp := testProvider()
	mp.DiffReturn = nil

	mp.ApplyFn = func(
		info *terraform.InstanceInfo,
		state *terraform.InstanceState,
		diff *terraform.InstanceDiff) (*terraform.InstanceState, error) {
		if !diff.Destroy {
			return &terraform.InstanceState{
				ID: "foo",
			}, nil
		}

		return nil, nil
	}

	var refreshCount int32
	mp.RefreshFn = func(*terraform.InstanceInfo, *terraform.InstanceState) (*terraform.InstanceState, error) {
		atomic.AddInt32(&refreshCount, 1)
		if atomic.LoadInt32(&refreshCount) == expectedRefresh-1 {
			return &terraform.InstanceState{
				ID:         "foo",
				Attributes: map[string]string{"foo": "bar"},
			}, nil
		} else if atomic.LoadInt32(&refreshCount) < expectedRefresh {
			return &terraform.InstanceState{ID: "foo"}, nil
		} else {
			return nil, nil
		}
	}

	mt := new(mockT)
	Test(mt, TestCase{
		Providers: map[string]terraform.ResourceProvider{
			"test": mp,
		},
		Steps: []TestStep{
			TestStep{
				Config: testConfigStr,
			},
		},
	})

	if !mt.failed() {
		t.Fatal("test didn't fail")
	}
	t.Logf("failure reason: %s", mt.failMessage())

	// See declaration of expectedRefresh for why that number
	if refreshCount != expectedRefresh {
		t.Fatalf("bad refresh count: %d", refreshCount)
	}
}

func TestTest_empty(t *testing.T) {
	destroyCalled := false
	checkDestroyFn := func(*terraform.State) error {
		destroyCalled = true
		return nil
	}

	mt := new(mockT)
	Test(mt, TestCase{
		CheckDestroy: checkDestroyFn,
	})

	if mt.failed() {
		t.Fatal("test failed")
	}
	if destroyCalled {
		t.Fatal("should not call check destroy if there is no steps")
	}
}

func TestTest_noEnv(t *testing.T) {
	// Unset the variable
	if err := os.Setenv(TestEnvVar, ""); err != nil {
		t.Fatalf("err: %s", err)
	}
	defer os.Setenv(TestEnvVar, "1")

	mt := new(mockT)
	Test(mt, TestCase{})

	if !mt.SkipCalled {
		t.Fatal("skip not called")
	}
}

func TestTest_preCheck(t *testing.T) {
	called := false

	mt := new(mockT)
	Test(mt, TestCase{
		PreCheck: func() { called = true },
	})

	if !called {
		t.Fatal("precheck should be called")
	}
}

func TestTest_stepError(t *testing.T) {
	mp := testProvider()
	mp.ApplyReturn = &terraform.InstanceState{
		ID: "foo",
	}

	checkDestroy := false

	checkDestroyFn := func(*terraform.State) error {
		checkDestroy = true
		return nil
	}

	checkStepFn := func(*terraform.State) error {
		return fmt.Errorf("error")
	}

	mt := new(mockT)
	Test(mt, TestCase{
		Providers: map[string]terraform.ResourceProvider{
			"test": mp,
		},
		CheckDestroy: checkDestroyFn,
		Steps: []TestStep{
			TestStep{
				Config: testConfigStr,
				Check:  checkStepFn,
			},
		},
	})

	if !mt.failed() {
		t.Fatal("test should've failed")
	}
	expected := "Step 0 error: Check failed: error"
	if mt.failMessage() != expected {
		t.Fatalf("Expected message: %s\n\ngot:\n\n%s", expected, mt.failMessage())
	}

	if !checkDestroy {
		t.Fatal("didn't call check for destroy")
	}
}

func TestComposeTestCheckFunc(t *testing.T) {
	cases := []struct {
		F      []TestCheckFunc
		Result string
	}{
		{
			F: []TestCheckFunc{
				func(*terraform.State) error { return nil },
			},
			Result: "",
		},

		{
			F: []TestCheckFunc{
				func(*terraform.State) error {
					return fmt.Errorf("error")
				},
				func(*terraform.State) error { return nil },
			},
			Result: "Check 1/2 error: error",
		},

		{
			F: []TestCheckFunc{
				func(*terraform.State) error { return nil },
				func(*terraform.State) error {
					return fmt.Errorf("error")
				},
			},
			Result: "Check 2/2 error: error",
		},

		{
			F: []TestCheckFunc{
				func(*terraform.State) error { return nil },
				func(*terraform.State) error { return nil },
			},
			Result: "",
		},
	}

	for i, tc := range cases {
		f := ComposeTestCheckFunc(tc.F...)
		err := f(nil)
		if err == nil {
			err = fmt.Errorf("")
		}
		if tc.Result != err.Error() {
			t.Fatalf("Case %d bad: %s", i, err)
		}
	}
}

// mockT implements TestT for testing
type mockT struct {
	ErrorCalled bool
	ErrorArgs   []interface{}
	FatalCalled bool
	FatalArgs   []interface{}
	SkipCalled  bool
	SkipArgs    []interface{}

	f bool
}

func (t *mockT) Error(args ...interface{}) {
	t.ErrorCalled = true
	t.ErrorArgs = args
	t.f = true
}

func (t *mockT) Fatal(args ...interface{}) {
	t.FatalCalled = true
	t.FatalArgs = args
	t.f = true
}

func (t *mockT) Skip(args ...interface{}) {
	t.SkipCalled = true
	t.SkipArgs = args
	t.f = true
}

func (t *mockT) failed() bool {
	return t.f
}

func (t *mockT) failMessage() string {
	if t.FatalCalled {
		return t.FatalArgs[0].(string)
	} else if t.ErrorCalled {
		return t.ErrorArgs[0].(string)
	} else if t.SkipCalled {
		return t.SkipArgs[0].(string)
	}

	return "unknown"
}

func testProvider() *terraform.MockResourceProvider {
	mp := new(terraform.MockResourceProvider)
	mp.DiffReturn = &terraform.InstanceDiff{
		Attributes: map[string]*terraform.ResourceAttrDiff{
			"foo": &terraform.ResourceAttrDiff{
				New: "bar",
			},
		},
	}
	mp.ResourcesReturn = []terraform.ResourceType{
		terraform.ResourceType{Name: "test_instance"},
	}

	return mp
}

const testConfigStr = `
resource "test_instance" "foo" {}
`
<|endoftext|>


<commit_before>package ssh

import (
	"code.google.com/p/go.crypto/ssh"
	"io"
)

type Keychain struct {
	keys []ssh.Signer
}

func (k *Keychain) Add(privateKey []byte) error {
	key, err := ssh.ParsePrivateKey(privateKey)

	if err != nil {
		return err
	}

	k.keys = append(k.keys, key)

	return nil
}

func (k *Keychain) Key(i int) ssh.PublicKey {
	if i < 0 || i >= len(k.keys) {
		return nil
	}

	return k.keys[i].PublicKey()
}

func (k *Keychain) Sign(i int, rand io.Reader, data []byte) ([]byte, error) {
	return k.keys[i].Sign(rand, data)
}
<commit_msg>Go didn't error for me. Build failed so making this match the ClientKeyring sig<commit_after>package ssh

import (
	"code.google.com/p/go.crypto/ssh"
	"io"
)

type Keychain struct {
	keys []ssh.Signer
}

func (k *Keychain) Add(privateKey []byte) error {
	key, err := ssh.ParsePrivateKey(privateKey)

	if err != nil {
		return err
	}

	k.keys = append(k.keys, key)

	return nil
}

func (k *Keychain) Key(i int) (ssh.PublicKey, error) {
	if i < 0 || i >= len(k.keys) {
		return nil, nil
	}

	return k.keys[i].PublicKey(), nil
}

func (k *Keychain) Sign(i int, rand io.Reader, data []byte) ([]byte, error) {
	return k.keys[i].Sign(rand, data)
}
<|endoftext|>


<commit_before>package zfs

import (
	"bufio"
	"bytes"
	"fmt"
	"strings"
	"time"
)

type (
	// SnapshotList represents a list of snapshots. These will always be sorted
	// by creation time.
	SnapshotList []*Snapshot
)

// NewShapshotList will create a new SnapshotList.
func NewShapshotList() (SnapshotList, error) {
	return SnapshotList{}, nil
}

// NewSnapshotListFromOutput will create a new SnapshotList from the output of
// "zfs list -t snapshot -o name,creation -s creation -H -p".
func NewSnapshotListFromOutput(output []byte, name string) (SnapshotList, error) {
	list, _ := NewShapshotList()
	var lastCreation time.Time

	scanner := bufio.NewScanner(bytes.NewReader(output))
	for scanner.Scan() {
		s, err := NewSnapshotFromLine(scanner.Text())
		if err != nil {
			return nil, err
		}

		if !strings.HasPrefix(s.Name, name+"@") {
			continue
		}

		if lastCreation.Sub(s.Creation) > time.Second {
			return nil, fmt.Errorf("output does not appear sorted. %d < %d", s.Creation.Unix(), lastCreation.Unix())
		}

		lastCreation = s.Creation

		list = append(list, s)
	}

	return list, nil
}

// Next will retrieve a pointer to the next Snapshot in l where the snapshot
// creation time is newer than or equal to from.
func (l SnapshotList) Next(from time.Time) *Snapshot {
	for _, snapshot := range l {
		if snapshot.Creation.Sub(from) >= 0 {
			return snapshot
		}
	}

	return nil
}

// Oldest will return a pointer to the oldest snapshot in l.
func (l SnapshotList) Oldest() *Snapshot {
	if len(l) < 1 {
		return nil
	}

	return l[0]
}

// Latest will return a pointer to the latest snapshot in l.
func (l SnapshotList) Latest() *Snapshot {
	if len(l) < 1 {
		return nil
	}

	return l[len(l)-1]
}

// String imeplements Stringer.
func (l SnapshotList) String() string {
	out := "[ "

	for _, s := range l {
		out += fmt.Sprintf("%s ", s.String())
	}

	return out + "]"
}

// KeepLatest will keep the num latest snapshots.
func (l SnapshotList) KeepLatest(num int) {
	start := len(l) - num

	if start < 0 {
		start = 0
	}

	for i := start; i < len(l); i++ {
		l[i].Keep = true
	}
}

// KeepNamed will keep all snapshots named in names.
func (l SnapshotList) KeepNamed(names []string) {
	// Start by indexing names for lookups.
	index := make(map[string]bool)
	for _, name := range names {
		index[name] = true
	}

	for _, snapshot := range l {
		snapshot.Keep = index[snapshot.SnapshotName()]
	}
}

// KeepOldest keeps the num oldest snapshots.
func (l SnapshotList) KeepOldest(num int) {
	for i := 0; i < num && i < len(l); i++ {
		l[i].Keep = true
	}
}

// Sieve will mark snapshots to keep according to start time and frequency.
func (l SnapshotList) Sieve(start time.Time, frequency time.Duration) {
	// The ZFS resolution on creation time is one second. If we get a frequency
	// below one second, we have to keep everything after start.
	if frequency < time.Second {
		for _, s := range l {
			if s.Creation.Sub(start) >= 0 {
				s.Keep = true
			}
		}

		return
	}

	for s := l.Next(start); s != nil; s = l.Next(s.Creation.Add(frequency)) {
		s.Keep = true
	}
}

// ResetSieve will mark all snapshots for deletion.
func (l SnapshotList) ResetSieve() {
	for _, s := range l {
		s.Keep = false
	}
}
<commit_msg>Only mark snapshots found for keeping, not unmark unfound ones.<commit_after>package zfs

import (
	"bufio"
	"bytes"
	"fmt"
	"strings"
	"time"
)

type (
	// SnapshotList represents a list of snapshots. These will always be sorted
	// by creation time.
	SnapshotList []*Snapshot
)

// NewShapshotList will create a new SnapshotList.
func NewShapshotList() (SnapshotList, error) {
	return SnapshotList{}, nil
}

// NewSnapshotListFromOutput will create a new SnapshotList from the output of
// "zfs list -t snapshot -o name,creation -s creation -H -p".
func NewSnapshotListFromOutput(output []byte, name string) (SnapshotList, error) {
	list, _ := NewShapshotList()
	var lastCreation time.Time

	scanner := bufio.NewScanner(bytes.NewReader(output))
	for scanner.Scan() {
		s, err := NewSnapshotFromLine(scanner.Text())
		if err != nil {
			return nil, err
		}

		if !strings.HasPrefix(s.Name, name+"@") {
			continue
		}

		if lastCreation.Sub(s.Creation) > time.Second {
			return nil, fmt.Errorf("output does not appear sorted. %d < %d", s.Creation.Unix(), lastCreation.Unix())
		}

		lastCreation = s.Creation

		list = append(list, s)
	}

	return list, nil
}

// Next will retrieve a pointer to the next Snapshot in l where the snapshot
// creation time is newer than or equal to from.
func (l SnapshotList) Next(from time.Time) *Snapshot {
	for _, snapshot := range l {
		if snapshot.Creation.Sub(from) >= 0 {
			return snapshot
		}
	}

	return nil
}

// Oldest will return a pointer to the oldest snapshot in l.
func (l SnapshotList) Oldest() *Snapshot {
	if len(l) < 1 {
		return nil
	}

	return l[0]
}

// Latest will return a pointer to the latest snapshot in l.
func (l SnapshotList) Latest() *Snapshot {
	if len(l) < 1 {
		return nil
	}

	return l[len(l)-1]
}

// String imeplements Stringer.
func (l SnapshotList) String() string {
	out := "[ "

	for _, s := range l {
		out += fmt.Sprintf("%s ", s.String())
	}

	return out + "]"
}

// KeepLatest will keep the num latest snapshots.
func (l SnapshotList) KeepLatest(num int) {
	start := len(l) - num

	if start < 0 {
		start = 0
	}

	for i := start; i < len(l); i++ {
		l[i].Keep = true
	}
}

// KeepNamed will keep all snapshots named in names.
func (l SnapshotList) KeepNamed(names []string) {
	// Start by indexing names for lookups.
	index := make(map[string]bool)
	for _, name := range names {
		index[name] = true
	}

	for _, snapshot := range l {
		if index[snapshot.SnapshotName()] {
			snapshot.Keep = true
		}
	}
}

// KeepOldest keeps the num oldest snapshots.
func (l SnapshotList) KeepOldest(num int) {
	for i := 0; i < num && i < len(l); i++ {
		l[i].Keep = true
	}
}

// Sieve will mark snapshots to keep according to start time and frequency.
func (l SnapshotList) Sieve(start time.Time, frequency time.Duration) {
	// The ZFS resolution on creation time is one second. If we get a frequency
	// below one second, we have to keep everything after start.
	if frequency < time.Second {
		for _, s := range l {
			if s.Creation.Sub(start) >= 0 {
				s.Keep = true
			}
		}

		return
	}

	for s := l.Next(start); s != nil; s = l.Next(s.Creation.Add(frequency)) {
		s.Keep = true
	}
}

// ResetSieve will mark all snapshots for deletion.
func (l SnapshotList) ResetSieve() {
	for _, s := range l {
		s.Keep = false
	}
}
<|endoftext|>