<commit_before>/* Copyright 2016 The Bazel Authors. 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.
*/

// Command gazelle is a BUILD file generator for Go projects.
// See "gazelle --help" for more details.
package main

import (
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"

	bf "github.com/bazelbuild/buildtools/build"
	"github.com/bazelbuild/rules_go/go/tools/gazelle/config"
	"github.com/bazelbuild/rules_go/go/tools/gazelle/merger"
	"github.com/bazelbuild/rules_go/go/tools/gazelle/packages"
	"github.com/bazelbuild/rules_go/go/tools/gazelle/rules"
	"github.com/bazelbuild/rules_go/go/tools/gazelle/wspace"
)

type emitFunc func(*config.Config, *bf.File) error

var modeFromName = map[string]emitFunc{
	"print": printFile,
	"fix":   fixFile,
	"diff":  diffFile,
}

func run(c *config.Config, emit emitFunc) {
	g := rules.NewGenerator(c)
	shouldProcessRoot := false
	didProcessRoot := false
	for _, dir := range c.Dirs {
		if c.RepoRoot == dir {
			shouldProcessRoot = true
		}
		packages.Walk(c, dir, func(pkg *packages.Package, oldFile *bf.File) {
			if pkg.Rel == "" {
				didProcessRoot = true
			}
			processPackage(c, g, emit, pkg, oldFile)
		})
	}
	if shouldProcessRoot && !didProcessRoot {
		// We did not process a package at the repository root. We need to put
		// a go_prefix rule there, even if there are no .go files in that directory.
		pkg := &packages.Package{Dir: c.RepoRoot}
		var oldFile *bf.File
		var oldData []byte
		oldPath, err := findBuildFile(c, c.RepoRoot)
		if os.IsNotExist(err) {
			goto processRoot
		}
		if err != nil {
			log.Print(err)
			return
		}
		oldData, err = ioutil.ReadFile(oldPath)
		if err != nil {
			log.Print(err)
			return
		}
		oldFile, err = bf.Parse(oldPath, oldData)
		if err != nil {
			log.Print(err)
			return
		}

	processRoot:
		processPackage(c, g, emit, pkg, oldFile)
	}
}

func processPackage(c *config.Config, g rules.Generator, emit emitFunc, pkg *packages.Package, oldFile *bf.File) {
	genFile := g.Generate(pkg)

	if oldFile == nil {
		// No existing file, so no merge required.
		bf.Rewrite(genFile, nil) // have buildifier 'format' our rules.
		if err := emit(c, genFile); err != nil {
			log.Print(err)
		}
		return
	}

	// Existing file, so merge and replace the old one.
	mergedFile := merger.MergeWithExisting(genFile, oldFile)
	if mergedFile == nil {
		// Ignored file. Don't emit.
		return
	}

	bf.Rewrite(mergedFile, nil) // have buildifier 'format' our rules.
	if err := emit(c, mergedFile); err != nil {
		log.Print(err)
		return
	}
}

func usage(fs *flag.FlagSet) {
	fmt.Fprintln(os.Stderr, `usage: gazelle [flags...] [package-dirs...]

Gazelle is a BUILD file generator for Go projects.

Currently its primary usage is to generate BUILD files for external dependencies
in a go_repository rule.
You can still use Gazelle for other purposes, but its interface can change without
notice.

It takes a list of paths to Go package directories [defaults to . if none given].
It recursively traverses its subpackages.
All the directories must be under the directory specified in -repo_root.
[if -repo_root is not given, gazelle searches $pwd and up for the WORKSPACE file]

There are several modes of gazelle.
In print mode, gazelle prints reconciled BUILD files to stdout.
In fix mode, gazelle creates BUILD files or updates existing ones.
In diff mode, gazelle shows diff.

FLAGS:
`)
	fs.PrintDefaults()
}

func main() {
	log.SetPrefix("gazelle: ")
	log.SetFlags(0) // don't print timestamps

	c, emit, err := newConfiguration(os.Args[1:])
	if err != nil {
		log.Fatal(err)
	}

	run(c, emit)
}

func newConfiguration(args []string) (*config.Config, emitFunc, error) {
	fs := flag.NewFlagSet("gazelle", flag.ContinueOnError)
	// Flag will call this on any parse error. Don't print usage unless
	// -h or -help were passed explicitly.
	fs.Usage = func() {}

	buildFileName := fs.String("build_file_name", "BUILD.bazel,BUILD", "comma-separated list of valid build file names.\nThe first element of the list is the name of output build files to generate.")
	buildTags := fs.String("build_tags", "", "comma-separated list of build tags. If not specified, Gazelle will not\n\tfilter sources with build constraints.")
	external := fs.String("external", "external", "external: resolve external packages with go_repository\n\tvendored: resolve external packages as packages in vendor/")
	goPrefix := fs.String("go_prefix", "", "go_prefix of the target workspace")
	repoRoot := fs.String("repo_root", "", "path to a directory which corresponds to go_prefix, otherwise gazelle searches for it.")
	mode := fs.String("mode", "fix", "print: prints all of the updated BUILD files\n\tfix: rewrites all of the BUILD files in place\n\tdiff: computes the rewrite but then just does a diff")
	if err := fs.Parse(args); err != nil {
		if err == flag.ErrHelp {
			usage(fs)
			os.Exit(0)
		}
		// flag already prints the error; don't print it again.
		log.Fatal("Try -help for more information.")
	}

	var c config.Config
	var err error

	c.Dirs = flag.Args()
	if len(c.Dirs) == 0 {
		c.Dirs = []string{"."}
	}
	for i := range c.Dirs {
		c.Dirs[i], err = filepath.Abs(c.Dirs[i])
		if err != nil {
			return nil, nil, err
		}
	}

	if *repoRoot != "" {
		c.RepoRoot = *repoRoot
	} else if len(c.Dirs) == 1 {
		c.RepoRoot, err = wspace.Find(c.Dirs[0])
		if err != nil {
			return nil, nil, fmt.Errorf("-repo_root not specified, and WORKSPACE cannot be found: %v", err)
		}
	} else {
		cwd, err := filepath.Abs(".")
		if err != nil {
			return nil, nil, err
		}
		c.RepoRoot, err = wspace.Find(cwd)
		if err != nil {
			return nil, nil, fmt.Errorf("-repo_root not specified, and WORKSPACE cannot be found: %v", err)
		}
	}

	for _, dir := range c.Dirs {
		if !isDescendingDir(dir, c.RepoRoot) {
			return nil, nil, fmt.Errorf("dir %q is not a subdirectory of repo root %q", dir, c.RepoRoot)
		}
	}

	c.ValidBuildFileNames = strings.Split(*buildFileName, ",")
	if len(c.ValidBuildFileNames) == 0 {
		return nil, nil, fmt.Errorf("no valid build file names specified")
	}

	c.GenericTags = make(config.BuildTags)
	for _, t := range strings.Split(*buildTags, ",") {
		if strings.HasPrefix(t, "!") {
			return nil, nil, fmt.Errorf("build tags can't be negated: %s", t)
		}
		c.GenericTags[t] = true
	}
	c.Platforms = config.DefaultPlatformTags
	c.PreprocessTags()

	c.GoPrefix = *goPrefix
	if c.GoPrefix == "" {
		c.GoPrefix, err = loadGoPrefix(&c)
		if err != nil {
			return nil, nil, fmt.Errorf("-go_prefix not set and not root BUILD file found")
		}
	}

	c.DepMode, err = config.DependencyModeFromString(*external)
	if err != nil {
		return nil, nil, err
	}

	emit, ok := modeFromName[*mode]
	if !ok {
		return nil, nil, fmt.Errorf("unrecognized emit mode: %q", *mode)
	}

	return &c, emit, err
}

func findBuildFile(c *config.Config, dir string) (string, error) {
	for _, base := range c.ValidBuildFileNames {
		p := filepath.Join(dir, base)
		fi, err := os.Stat(p)
		if err == nil {
			if fi.Mode().IsRegular() {
				return p, nil
			}
			continue
		}
		if !os.IsNotExist(err) {
			return "", err
		}
	}
	return "", os.ErrNotExist
}

func loadGoPrefix(c *config.Config) (string, error) {
	p, err := findBuildFile(c, c.RepoRoot)
	if err != nil {
		return "", err
	}
	b, err := ioutil.ReadFile(p)
	if err != nil {
		return "", err
	}
	f, err := bf.Parse(p, b)
	if err != nil {
		return "", err
	}
	for _, s := range f.Stmt {
		c, ok := s.(*bf.CallExpr)
		if !ok {
			continue
		}
		l, ok := c.X.(*bf.LiteralExpr)
		if !ok {
			continue
		}
		if l.Token != "go_prefix" {
			continue
		}
		if len(c.List) != 1 {
			return "", fmt.Errorf("found go_prefix(%v) with too many args", c.List)
		}
		v, ok := c.List[0].(*bf.StringExpr)
		if !ok {
			return "", fmt.Errorf("found go_prefix(%v) which is not a string", c.List)
		}
		return v.Value, nil
	}
	return "", errors.New("-go_prefix not set, and no go_prefix in root BUILD file")
}

func isDescendingDir(dir, root string) bool {
	if dir == root {
		return true
	}
	return strings.HasPrefix(dir, fmt.Sprintf("%s%c", root, filepath.Separator))
}
<commit_msg>Get directories from parsed FlagSet (#596)<commit_after>/* Copyright 2016 The Bazel Authors. 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.
*/

// Command gazelle is a BUILD file generator for Go projects.
// See "gazelle --help" for more details.
package main

import (
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"

	bf "github.com/bazelbuild/buildtools/build"
	"github.com/bazelbuild/rules_go/go/tools/gazelle/config"
	"github.com/bazelbuild/rules_go/go/tools/gazelle/merger"
	"github.com/bazelbuild/rules_go/go/tools/gazelle/packages"
	"github.com/bazelbuild/rules_go/go/tools/gazelle/rules"
	"github.com/bazelbuild/rules_go/go/tools/gazelle/wspace"
)

type emitFunc func(*config.Config, *bf.File) error

var modeFromName = map[string]emitFunc{
	"print": printFile,
	"fix":   fixFile,
	"diff":  diffFile,
}

func run(c *config.Config, emit emitFunc) {
	g := rules.NewGenerator(c)
	shouldProcessRoot := false
	didProcessRoot := false
	for _, dir := range c.Dirs {
		if c.RepoRoot == dir {
			shouldProcessRoot = true
		}
		packages.Walk(c, dir, func(pkg *packages.Package, oldFile *bf.File) {
			if pkg.Rel == "" {
				didProcessRoot = true
			}
			processPackage(c, g, emit, pkg, oldFile)
		})
	}
	if shouldProcessRoot && !didProcessRoot {
		// We did not process a package at the repository root. We need to put
		// a go_prefix rule there, even if there are no .go files in that directory.
		pkg := &packages.Package{Dir: c.RepoRoot}
		var oldFile *bf.File
		var oldData []byte
		oldPath, err := findBuildFile(c, c.RepoRoot)
		if os.IsNotExist(err) {
			goto processRoot
		}
		if err != nil {
			log.Print(err)
			return
		}
		oldData, err = ioutil.ReadFile(oldPath)
		if err != nil {
			log.Print(err)
			return
		}
		oldFile, err = bf.Parse(oldPath, oldData)
		if err != nil {
			log.Print(err)
			return
		}

	processRoot:
		processPackage(c, g, emit, pkg, oldFile)
	}
}

func processPackage(c *config.Config, g rules.Generator, emit emitFunc, pkg *packages.Package, oldFile *bf.File) {
	genFile := g.Generate(pkg)

	if oldFile == nil {
		// No existing file, so no merge required.
		bf.Rewrite(genFile, nil) // have buildifier 'format' our rules.
		if err := emit(c, genFile); err != nil {
			log.Print(err)
		}
		return
	}

	// Existing file, so merge and replace the old one.
	mergedFile := merger.MergeWithExisting(genFile, oldFile)
	if mergedFile == nil {
		// Ignored file. Don't emit.
		return
	}

	bf.Rewrite(mergedFile, nil) // have buildifier 'format' our rules.
	if err := emit(c, mergedFile); err != nil {
		log.Print(err)
		return
	}
}

func usage(fs *flag.FlagSet) {
	fmt.Fprintln(os.Stderr, `usage: gazelle [flags...] [package-dirs...]

Gazelle is a BUILD file generator for Go projects.

Currently its primary usage is to generate BUILD files for external dependencies
in a go_repository rule.
You can still use Gazelle for other purposes, but its interface can change without
notice.

It takes a list of paths to Go package directories [defaults to . if none given].
It recursively traverses its subpackages.
All the directories must be under the directory specified in -repo_root.
[if -repo_root is not given, gazelle searches $pwd and up for the WORKSPACE file]

There are several modes of gazelle.
In print mode, gazelle prints reconciled BUILD files to stdout.
In fix mode, gazelle creates BUILD files or updates existing ones.
In diff mode, gazelle shows diff.

FLAGS:
`)
	fs.PrintDefaults()
}

func main() {
	log.SetPrefix("gazelle: ")
	log.SetFlags(0) // don't print timestamps

	c, emit, err := newConfiguration(os.Args[1:])
	if err != nil {
		log.Fatal(err)
	}

	run(c, emit)
}

func newConfiguration(args []string) (*config.Config, emitFunc, error) {
	fs := flag.NewFlagSet("gazelle", flag.ContinueOnError)
	// Flag will call this on any parse error. Don't print usage unless
	// -h or -help were passed explicitly.
	fs.Usage = func() {}

	buildFileName := fs.String("build_file_name", "BUILD.bazel,BUILD", "comma-separated list of valid build file names.\nThe first element of the list is the name of output build files to generate.")
	buildTags := fs.String("build_tags", "", "comma-separated list of build tags. If not specified, Gazelle will not\n\tfilter sources with build constraints.")
	external := fs.String("external", "external", "external: resolve external packages with go_repository\n\tvendored: resolve external packages as packages in vendor/")
	goPrefix := fs.String("go_prefix", "", "go_prefix of the target workspace")
	repoRoot := fs.String("repo_root", "", "path to a directory which corresponds to go_prefix, otherwise gazelle searches for it.")
	mode := fs.String("mode", "fix", "print: prints all of the updated BUILD files\n\tfix: rewrites all of the BUILD files in place\n\tdiff: computes the rewrite but then just does a diff")
	if err := fs.Parse(args); err != nil {
		if err == flag.ErrHelp {
			usage(fs)
			os.Exit(0)
		}
		// flag already prints the error; don't print it again.
		log.Fatal("Try -help for more information.")
	}

	var c config.Config
	var err error

	c.Dirs = fs.Args()
	if len(c.Dirs) == 0 {
		c.Dirs = []string{"."}
	}
	for i := range c.Dirs {
		c.Dirs[i], err = filepath.Abs(c.Dirs[i])
		if err != nil {
			return nil, nil, err
		}
	}

	if *repoRoot != "" {
		c.RepoRoot = *repoRoot
	} else if len(c.Dirs) == 1 {
		c.RepoRoot, err = wspace.Find(c.Dirs[0])
		if err != nil {
			return nil, nil, fmt.Errorf("-repo_root not specified, and WORKSPACE cannot be found: %v", err)
		}
	} else {
		cwd, err := filepath.Abs(".")
		if err != nil {
			return nil, nil, err
		}
		c.RepoRoot, err = wspace.Find(cwd)
		if err != nil {
			return nil, nil, fmt.Errorf("-repo_root not specified, and WORKSPACE cannot be found: %v", err)
		}
	}

	for _, dir := range c.Dirs {
		if !isDescendingDir(dir, c.RepoRoot) {
			return nil, nil, fmt.Errorf("dir %q is not a subdirectory of repo root %q", dir, c.RepoRoot)
		}
	}

	c.ValidBuildFileNames = strings.Split(*buildFileName, ",")
	if len(c.ValidBuildFileNames) == 0 {
		return nil, nil, fmt.Errorf("no valid build file names specified")
	}

	c.GenericTags = make(config.BuildTags)
	for _, t := range strings.Split(*buildTags, ",") {
		if strings.HasPrefix(t, "!") {
			return nil, nil, fmt.Errorf("build tags can't be negated: %s", t)
		}
		c.GenericTags[t] = true
	}
	c.Platforms = config.DefaultPlatformTags
	c.PreprocessTags()

	c.GoPrefix = *goPrefix
	if c.GoPrefix == "" {
		c.GoPrefix, err = loadGoPrefix(&c)
		if err != nil {
			return nil, nil, fmt.Errorf("-go_prefix not set and not root BUILD file found")
		}
	}

	c.DepMode, err = config.DependencyModeFromString(*external)
	if err != nil {
		return nil, nil, err
	}

	emit, ok := modeFromName[*mode]
	if !ok {
		return nil, nil, fmt.Errorf("unrecognized emit mode: %q", *mode)
	}

	return &c, emit, err
}

func findBuildFile(c *config.Config, dir string) (string, error) {
	for _, base := range c.ValidBuildFileNames {
		p := filepath.Join(dir, base)
		fi, err := os.Stat(p)
		if err == nil {
			if fi.Mode().IsRegular() {
				return p, nil
			}
			continue
		}
		if !os.IsNotExist(err) {
			return "", err
		}
	}
	return "", os.ErrNotExist
}

func loadGoPrefix(c *config.Config) (string, error) {
	p, err := findBuildFile(c, c.RepoRoot)
	if err != nil {
		return "", err
	}
	b, err := ioutil.ReadFile(p)
	if err != nil {
		return "", err
	}
	f, err := bf.Parse(p, b)
	if err != nil {
		return "", err
	}
	for _, s := range f.Stmt {
		c, ok := s.(*bf.CallExpr)
		if !ok {
			continue
		}
		l, ok := c.X.(*bf.LiteralExpr)
		if !ok {
			continue
		}
		if l.Token != "go_prefix" {
			continue
		}
		if len(c.List) != 1 {
			return "", fmt.Errorf("found go_prefix(%v) with too many args", c.List)
		}
		v, ok := c.List[0].(*bf.StringExpr)
		if !ok {
			return "", fmt.Errorf("found go_prefix(%v) which is not a string", c.List)
		}
		return v.Value, nil
	}
	return "", errors.New("-go_prefix not set, and no go_prefix in root BUILD file")
}

func isDescendingDir(dir, root string) bool {
	if dir == root {
		return true
	}
	return strings.HasPrefix(dir, fmt.Sprintf("%s%c", root, filepath.Separator))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"

	"github.com/bitfinexcom/bitfinex-api-go/v2"
	"github.com/bitfinexcom/bitfinex-api-go/v2/rest"
	"github.com/davecgh/go-spew/spew"
)

// Set BFX_API_KEY and BFX_API_SECRET as :
//
// export BFX_API_KEY=YOUR_API_KEY
// export BFX_API_SECRET=YOUR_API_SECRET
//
// you can obtain it from https://www.bitfinex.com/api

func main() {
	key := os.Getenv("BFX_API_KEY")
	secret := os.Getenv("BFX_API_SECRET")
	c := rest.NewClient().Credentials(key, secret)

	offers(c)
	offerHistory(c)
	loans(c)
	loansHistory(c)
	activeCredits(c)
	creditsHistory(c)
	fundingTrades(c)
	keepFunding(c)

	/********* submit a new funding offer ***********/
	fo, err := c.Funding.SubmitOffer(&bitfinex.FundingOfferRequest{
		Type:   "LIMIT",
		Symbol: "fUSD",
		Amount: 1000,
		Rate:   0.012,
		Period: 7,
		Hidden: true,
	})
	if err != nil {
		panic(err)
	}
	newOffer := fo.NotifyInfo.(*bitfinex.FundingOfferNew)

	/********* cancel funding offer ***********/
	fc, err := c.Funding.CancelOffer(&bitfinex.FundingOfferCancelRequest{
		Id: newOffer.ID,
	})
	if err != nil {
		panic(err)
	}
	fmt.Println(fc)
}

func offers(c *rest.Client) {
	// active funding offers
	snap, err := c.Funding.Offers("fUSD")
	if err != nil {
		panic(err)
	}
	for _, item := range snap.Snapshot {
		fmt.Println(item)
	}
}

func offerHistory(c *rest.Client) {
	// funding offer history
	snapHist, err := c.Funding.OfferHistory("fUSD")
	if err != nil {
		panic(err)
	}
	for _, item := range snapHist.Snapshot {
		fmt.Println(item)
	}
}

func loans(c *rest.Client) {
	// active loans
	snapLoans, err := c.Funding.Loans("fUSD")
	if err != nil {
		panic(err)
	}
	for _, item := range snapLoans.Snapshot {
		fmt.Println(item)
	}
}

func loansHistory(c *rest.Client) {
	napLoansHist, err := c.Funding.LoansHistory("fUSD")
	if err != nil {
		panic(err)
	}
	for _, item := range napLoansHist.Snapshot {
		fmt.Println(item)
	}
}

func activeCredits(c *rest.Client) {
	// active credits
	snapCredits, err := c.Funding.Credits("fUSD")
	if err != nil {
		panic(err)
	}
	for _, item := range snapCredits.Snapshot {
		fmt.Println(item)
	}
}

func creditsHistory(c *rest.Client) {
	napCreditsHist, err := c.Funding.CreditsHistory("fUSD")
	if err != nil {
		panic(err)
	}
	for _, item := range napCreditsHist.Snapshot {
		fmt.Println(item)
	}
}

func fundingTrades(c *rest.Client) {
	napTradesHist, err := c.Funding.Trades("fUSD")
	if err != nil {
		panic(err)
	}
	for _, item := range napTradesHist.Snapshot {
		fmt.Println(item)
	}
}

func keepFunding(c *rest.Client) {
	// keep funding
	resp, err := c.Funding.KeepFunding(rest.KeepFundingRequest{
		Type: "credit",
		ID:   12345, // Insert correct ID
	})
	if err != nil {
		log.Fatalf("KeepFunding error: %s", err)
	}

	spew.Dump(resp)
}
<commit_msg>examples/v2/rest-funding/main.go updating fundingoffer usage example<commit_after>package main

import (
	"fmt"
	"log"
	"os"

	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/fundingoffer"
	"github.com/bitfinexcom/bitfinex-api-go/v2/rest"
	"github.com/davecgh/go-spew/spew"
)

// Set BFX_API_KEY and BFX_API_SECRET as :
//
// export BFX_API_KEY=YOUR_API_KEY
// export BFX_API_SECRET=YOUR_API_SECRET
//
// you can obtain it from https://www.bitfinex.com/api

func main() {
	key := os.Getenv("BFX_API_KEY")
	secret := os.Getenv("BFX_API_SECRET")
	c := rest.NewClient().Credentials(key, secret)

	offers(c)
	offerHistory(c)
	loans(c)
	loansHistory(c)
	activeCredits(c)
	creditsHistory(c)
	fundingTrades(c)
	keepFunding(c)

	/********* submit a new funding offer ***********/
	fo, err := c.Funding.SubmitOffer(&fundingoffer.SubmitRequest{
		Type:   "LIMIT",
		Symbol: "fUSD",
		Amount: 1000,
		Rate:   0.012,
		Period: 7,
		Hidden: true,
	})
	if err != nil {
		panic(err)
	}
	newOffer := fo.NotifyInfo.(*fundingoffer.New)

	/********* cancel funding offer ***********/
	fc, err := c.Funding.CancelOffer(&fundingoffer.CancelRequest{
		ID: newOffer.ID,
	})
	if err != nil {
		panic(err)
	}
	fmt.Println(fc)
}

func offers(c *rest.Client) {
	// active funding offers
	snap, err := c.Funding.Offers("fUSD")
	if err != nil {
		panic(err)
	}
	for _, item := range snap.Snapshot {
		fmt.Println(item)
	}
}

func offerHistory(c *rest.Client) {
	// funding offer history
	snapHist, err := c.Funding.OfferHistory("fUSD")
	if err != nil {
		panic(err)
	}
	for _, item := range snapHist.Snapshot {
		fmt.Println(item)
	}
}

func loans(c *rest.Client) {
	// active loans
	snapLoans, err := c.Funding.Loans("fUSD")
	if err != nil {
		panic(err)
	}
	for _, item := range snapLoans.Snapshot {
		fmt.Println(item)
	}
}

func loansHistory(c *rest.Client) {
	napLoansHist, err := c.Funding.LoansHistory("fUSD")
	if err != nil {
		panic(err)
	}
	for _, item := range napLoansHist.Snapshot {
		fmt.Println(item)
	}
}

func activeCredits(c *rest.Client) {
	// active credits
	snapCredits, err := c.Funding.Credits("fUSD")
	if err != nil {
		panic(err)
	}
	for _, item := range snapCredits.Snapshot {
		fmt.Println(item)
	}
}

func creditsHistory(c *rest.Client) {
	napCreditsHist, err := c.Funding.CreditsHistory("fUSD")
	if err != nil {
		panic(err)
	}
	for _, item := range napCreditsHist.Snapshot {
		fmt.Println(item)
	}
}

func fundingTrades(c *rest.Client) {
	napTradesHist, err := c.Funding.Trades("fUSD")
	if err != nil {
		panic(err)
	}
	for _, item := range napTradesHist.Snapshot {
		fmt.Println(item)
	}
}

func keepFunding(c *rest.Client) {
	// keep funding
	resp, err := c.Funding.KeepFunding(rest.KeepFundingRequest{
		Type: "credit",
		ID:   12345, // Insert correct ID
	})
	if err != nil {
		log.Fatalf("KeepFunding error: %s", err)
	}

	spew.Dump(resp)
}
<|endoftext|>


<commit_before>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package avalanche

import (
	"fmt"

	"github.com/ava-labs/gecko/cache"
	"github.com/ava-labs/gecko/ids"
	"github.com/ava-labs/gecko/snow/choices"
	"github.com/ava-labs/gecko/snow/consensus/avalanche"
	"github.com/ava-labs/gecko/snow/engine/common"
	"github.com/ava-labs/gecko/snow/engine/common/queue"
	"github.com/ava-labs/gecko/utils/formatting"
	"github.com/prometheus/client_golang/prometheus"
)

const (
	// We cache processed vertices where height = c * stripeDistance for c = {1,2,3...}
	// This forms a "stripe" of cached DAG vertices at height stripeDistance, 2*stripeDistance, etc.
	// This helps to limit the number of repeated DAG traversals performed
	stripeDistance = 2000
	stripeWidth    = 5
	cacheSize      = 100000
)

// BootstrapConfig ...
type BootstrapConfig struct {
	common.Config

	// VtxBlocked tracks operations that are blocked on vertices
	// TxBlocked tracks operations that are blocked on transactions
	VtxBlocked, TxBlocked *queue.Jobs

	State State
	VM    DAGVM
}

type bootstrapper struct {
	BootstrapConfig
	metrics
	common.Bootstrapper

	// number of vertices fetched so far
	numFetched uint32

	// tracks which validators were asked for which containers in which requests
	outstandingRequests common.Requests

	// IDs of vertices that we will send a GetAncestors request for once we are
	// not at the max number of outstanding requests
	needToFetch ids.Set

	// Contains IDs of vertices that have recently been processed
	processedCache *cache.LRU

	// true if bootstrapping is done
	finished bool

	// Called when bootstrapping is done
	onFinished func() error
}

// Initialize this engine.
func (b *bootstrapper) Initialize(config BootstrapConfig) error {
	b.BootstrapConfig = config
	b.processedCache = &cache.LRU{Size: cacheSize}

	b.VtxBlocked.SetParser(&vtxParser{
		log:         config.Context.Log,
		numAccepted: b.numBSVtx,
		numDropped:  b.numBSDroppedVtx,
		state:       b.State,
	})

	b.TxBlocked.SetParser(&txParser{
		log:         config.Context.Log,
		numAccepted: b.numBSTx,
		numDropped:  b.numBSDroppedTx,
		vm:          b.VM,
	})

	config.Bootstrapable = b
	b.Bootstrapper.Initialize(config.Config)
	return nil
}

// CurrentAcceptedFrontier ...
func (b *bootstrapper) CurrentAcceptedFrontier() ids.Set {
	acceptedFrontier := ids.Set{}
	acceptedFrontier.Add(b.State.Edge()...)
	return acceptedFrontier
}

// FilterAccepted ...
func (b *bootstrapper) FilterAccepted(containerIDs ids.Set) ids.Set {
	acceptedVtxIDs := ids.Set{}
	for _, vtxID := range containerIDs.List() {
		if vtx, err := b.State.GetVertex(vtxID); err == nil && vtx.Status() == choices.Accepted {
			acceptedVtxIDs.Add(vtxID)
		}
	}
	return acceptedVtxIDs
}

// Fetch vertices and their ancestors from the set of vertices that are needed
// to be fetched.
func (b *bootstrapper) fetch(vtxIDs ...ids.ID) error {
	b.needToFetch.Add(vtxIDs...)
	for b.needToFetch.Len() > 0 && b.outstandingRequests.Len() < common.MaxOutstandingRequests {
		vtxID := b.needToFetch.CappedList(1)[0]
		b.needToFetch.Remove(vtxID)

		// Make sure we haven't already requested this vertex
		if b.outstandingRequests.Contains(vtxID) {
			continue
		}

		// Make sure we don't already have this vertex
		if _, err := b.State.GetVertex(vtxID); err == nil {
			continue
		}

		validators := b.BootstrapConfig.Validators.Sample(1) // validator to send request to
		if len(validators) == 0 {
			return fmt.Errorf("Dropping request for %s as there are no validators", vtxID)
		}
		validatorID := validators[0].ID()
		b.RequestID++

		b.outstandingRequests.Add(validatorID, b.RequestID, vtxID)
		b.needToFetch.Remove(vtxID)                                            // maintains invariant that intersection with outstandingRequests is empty
		b.BootstrapConfig.Sender.GetAncestors(validatorID, b.RequestID, vtxID) // request vertex and ancestors
	}
	return b.finish()
}

// Process vertices
func (b *bootstrapper) process(vtxs ...avalanche.Vertex) error {
	toProcess := newMaxVertexHeap()
	for _, vtx := range vtxs {
		if _, ok := b.processedCache.Get(vtx.ID()); !ok { // only process if we haven't already
			toProcess.Push(vtx)
		}
	}

	for toProcess.Len() > 0 {
		vtx := toProcess.Pop()
		vtxID := vtx.ID()

		switch vtx.Status() {
		case choices.Unknown:
			b.needToFetch.Add(vtxID)
		case choices.Rejected:
			b.needToFetch.Remove(vtxID)
			return fmt.Errorf("tried to accept %s even though it was previously rejected", vtx.ID())
		case choices.Processing:
			b.needToFetch.Remove(vtxID)

			if err := b.VtxBlocked.Push(&vertexJob{
				log:         b.BootstrapConfig.Context.Log,
				numAccepted: b.numBSVtx,
				numDropped:  b.numBSDroppedVtx,
				vtx:         vtx,
			}); err == nil {
				b.numBSBlockedVtx.Inc()
				b.numFetched++ // Progress tracker
				if b.numFetched%common.StatusUpdateFrequency == 0 {
					b.BootstrapConfig.Context.Log.Info("fetched %d vertices", b.numFetched)
				}
			} else {
				b.BootstrapConfig.Context.Log.Verbo("couldn't push to vtxBlocked: %s", err)
			}
			for _, tx := range vtx.Txs() {
				if err := b.TxBlocked.Push(&txJob{
					log:         b.BootstrapConfig.Context.Log,
					numAccepted: b.numBSTx,
					numDropped:  b.numBSDroppedTx,
					tx:          tx,
				}); err == nil {
					b.numBSBlockedTx.Inc()
				} else {
					b.BootstrapConfig.Context.Log.Verbo("couldn't push to txBlocked: %s", err)
				}
			}
			for _, parent := range vtx.Parents() {
				if _, ok := b.processedCache.Get(parent.ID()); !ok { // already processed this
					toProcess.Push(parent)
				}
			}
			if vtx.Height()%stripeDistance < stripeWidth {
				b.processedCache.Put(vtx.ID(), nil)
			}
		}
	}

	if err := b.VtxBlocked.Commit(); err != nil {
		return err
	}
	if err := b.TxBlocked.Commit(); err != nil {
		return err
	}

	return b.fetch()
}

// MultiPut handles the receipt of multiple containers. Should be received in response to a GetAncestors message to [vdr]
// with request ID [requestID]. Expects vtxs[0] to be the vertex requested in the corresponding GetAncestors.
func (b *bootstrapper) MultiPut(vdr ids.ShortID, requestID uint32, vtxs [][]byte) error {
	if lenVtxs := len(vtxs); lenVtxs > common.MaxContainersPerMultiPut {
		b.BootstrapConfig.Context.Log.Debug("MultiPut(%s, %d) contains more than maximum number of vertices", vdr, requestID)
		return b.GetAncestorsFailed(vdr, requestID)
	} else if lenVtxs == 0 {
		b.BootstrapConfig.Context.Log.Debug("MultiPut(%s, %d) contains no vertices", vdr, requestID)
		return b.GetAncestorsFailed(vdr, requestID)
	}

	// Make sure this is in response to a request we made
	neededVtxID, needed := b.outstandingRequests.Remove(vdr, requestID)
	if !needed { // this message isn't in response to a request we made
		b.BootstrapConfig.Context.Log.Debug("received unexpected MultiPut from %s with ID %d", vdr, requestID)
		return nil
	}

	neededVtx, err := b.State.ParseVertex(vtxs[0]) // the vertex we requested
	if err != nil {
		b.BootstrapConfig.Context.Log.Debug("Failed to parse requested vertex %s: %w", neededVtxID, err)
		b.BootstrapConfig.Context.Log.Verbo("vertex: %s", formatting.DumpBytes{Bytes: vtxs[0]})
		return b.fetch(neededVtxID)
	} else if actualID := neededVtx.ID(); !actualID.Equals(neededVtxID) {
		b.BootstrapConfig.Context.Log.Debug("expected the first block to be the requested block, %s, but is %s", neededVtxID, actualID)
		return b.fetch(neededVtxID)
	}

	processVertices := make([]avalanche.Vertex, 1, len(vtxs))
	processVertices[0] = neededVtx

	for _, vtxBytes := range vtxs[1:] { // Parse/persist all the vertices
		if vtx, err := b.State.ParseVertex(vtxBytes); err != nil { // Persists the vtx
			b.BootstrapConfig.Context.Log.Debug("Failed to parse vertex: %w", err)
			b.BootstrapConfig.Context.Log.Verbo("vertex: %s", formatting.DumpBytes{Bytes: vtxBytes})
		} else {
			processVertices = append(processVertices, vtx)
			b.needToFetch.Remove(vtx.ID()) // No need to fetch this vertex since we have it now
		}
	}

	return b.process(processVertices...)
}

// GetAncestorsFailed is called when a GetAncestors message we sent fails
func (b *bootstrapper) GetAncestorsFailed(vdr ids.ShortID, requestID uint32) error {
	vtxID, ok := b.outstandingRequests.Remove(vdr, requestID)
	if !ok {
		b.BootstrapConfig.Context.Log.Debug("GetAncestorsFailed(%s, %d) called but there was no outstanding request to this validator with this ID", vdr, requestID)
		return nil
	}
	// Send another request for the vertex
	return b.fetch(vtxID)
}

// ForceAccepted ...
func (b *bootstrapper) ForceAccepted(acceptedContainerIDs ids.Set) error {
	if err := b.VM.Bootstrapping(); err != nil {
		return fmt.Errorf("failed to notify VM that bootstrapping has started: %w",
			err)
	}

	storedVtxs := make([]avalanche.Vertex, 0, acceptedContainerIDs.Len())
	for _, vtxID := range acceptedContainerIDs.List() {
		if vtx, err := b.State.GetVertex(vtxID); err == nil {
			storedVtxs = append(storedVtxs, vtx)
		} else {
			b.needToFetch.Add(vtxID)
		}
	}
	return b.process(storedVtxs...)
}

// Finish bootstrapping
func (b *bootstrapper) finish() error {
	if b.finished || b.outstandingRequests.Len() > 0 || b.needToFetch.Len() > 0 {
		return nil
	}
	b.BootstrapConfig.Context.Log.Info("finished fetching %d vertices. executing transaction state transitions...",
		b.numFetched)

	if err := b.executeAll(b.TxBlocked, b.numBSBlockedTx); err != nil {
		return err
	}

	b.BootstrapConfig.Context.Log.Info("executing vertex state transitions...")

	if err := b.executeAll(b.VtxBlocked, b.numBSBlockedVtx); err != nil {
		return err
	}

	if err := b.VM.Bootstrapped(); err != nil {
		return fmt.Errorf("failed to notify VM that bootstrapping has finished: %w",
			err)
	}

	// Start consensus
	if err := b.onFinished(); err != nil {
		return err
	}
	b.finished = true
	return nil
}

func (b *bootstrapper) executeAll(jobs *queue.Jobs, numBlocked prometheus.Gauge) error {
	numExecuted := 0
	for job, err := jobs.Pop(); err == nil; job, err = jobs.Pop() {
		numBlocked.Dec()
		b.BootstrapConfig.Context.Log.Debug("Executing: %s", job.ID())
		if err := jobs.Execute(job); err != nil {
			b.BootstrapConfig.Context.Log.Error("Error executing: %s", err)
			return err
		}
		if err := jobs.Commit(); err != nil {
			return err
		}
		numExecuted++
		if numExecuted%common.StatusUpdateFrequency == 0 { // Periodically print progress
			b.BootstrapConfig.Context.Log.Info("executed %d operations", numExecuted)
		}
	}
	b.BootstrapConfig.Context.Log.Info("executed %d operations", numExecuted)
	return nil
}
<commit_msg>add comments<commit_after>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package avalanche

import (
	"fmt"

	"github.com/ava-labs/gecko/cache"
	"github.com/ava-labs/gecko/ids"
	"github.com/ava-labs/gecko/snow/choices"
	"github.com/ava-labs/gecko/snow/consensus/avalanche"
	"github.com/ava-labs/gecko/snow/engine/common"
	"github.com/ava-labs/gecko/snow/engine/common/queue"
	"github.com/ava-labs/gecko/utils/formatting"
	"github.com/prometheus/client_golang/prometheus"
)

const (
	// We cache processed vertices where height = c * stripeDistance for c = {1,2,3...}
	// This forms a "stripe" of cached DAG vertices at height stripeDistance, 2*stripeDistance, etc.
	// This helps to limit the number of repeated DAG traversals performed
	stripeDistance = 2000
	stripeWidth    = 5
	cacheSize      = 100000
)

// BootstrapConfig ...
type BootstrapConfig struct {
	common.Config

	// VtxBlocked tracks operations that are blocked on vertices
	// TxBlocked tracks operations that are blocked on transactions
	VtxBlocked, TxBlocked *queue.Jobs

	State State
	VM    DAGVM
}

type bootstrapper struct {
	BootstrapConfig
	metrics
	common.Bootstrapper

	// number of vertices fetched so far
	numFetched uint32

	// tracks which validators were asked for which containers in which requests
	outstandingRequests common.Requests

	// IDs of vertices that we will send a GetAncestors request for once we are
	// not at the max number of outstanding requests
	needToFetch ids.Set

	// Contains IDs of vertices that have recently been processed
	processedCache *cache.LRU

	// true if bootstrapping is done
	finished bool

	// Called when bootstrapping is done
	onFinished func() error
}

// Initialize this engine.
func (b *bootstrapper) Initialize(config BootstrapConfig) error {
	b.BootstrapConfig = config
	b.processedCache = &cache.LRU{Size: cacheSize}

	b.VtxBlocked.SetParser(&vtxParser{
		log:         config.Context.Log,
		numAccepted: b.numBSVtx,
		numDropped:  b.numBSDroppedVtx,
		state:       b.State,
	})

	b.TxBlocked.SetParser(&txParser{
		log:         config.Context.Log,
		numAccepted: b.numBSTx,
		numDropped:  b.numBSDroppedTx,
		vm:          b.VM,
	})

	config.Bootstrapable = b
	b.Bootstrapper.Initialize(config.Config)
	return nil
}

// CurrentAcceptedFrontier returns the set of vertices that this node has accepted
// that have no accepted children
func (b *bootstrapper) CurrentAcceptedFrontier() ids.Set {
	acceptedFrontier := ids.Set{}
	acceptedFrontier.Add(b.State.Edge()...)
	return acceptedFrontier
}

// FilterAccepted returns the IDs of vertices in [containerIDs] that this node has accepted
func (b *bootstrapper) FilterAccepted(containerIDs ids.Set) ids.Set {
	acceptedVtxIDs := ids.Set{}
	for _, vtxID := range containerIDs.List() {
		if vtx, err := b.State.GetVertex(vtxID); err == nil && vtx.Status() == choices.Accepted {
			acceptedVtxIDs.Add(vtxID)
		}
	}
	return acceptedVtxIDs
}

// Add the vertices in [vtxIDs] to the set of vertices that we need to fetch,
// and then fetch vertices (and their ancestors) until either there are no more
// to fetch or we are at the maximum number of outstanding requests.
func (b *bootstrapper) fetch(vtxIDs ...ids.ID) error {
	b.needToFetch.Add(vtxIDs...)
	for b.needToFetch.Len() > 0 && b.outstandingRequests.Len() < common.MaxOutstandingRequests {
		vtxID := b.needToFetch.CappedList(1)[0]
		b.needToFetch.Remove(vtxID)

		// Make sure we haven't already requested this vertex
		if b.outstandingRequests.Contains(vtxID) {
			continue
		}

		// Make sure we don't already have this vertex
		if _, err := b.State.GetVertex(vtxID); err == nil {
			continue
		}

		validators := b.BootstrapConfig.Validators.Sample(1) // validator to send request to
		if len(validators) == 0 {
			return fmt.Errorf("Dropping request for %s as there are no validators", vtxID)
		}
		validatorID := validators[0].ID()
		b.RequestID++

		b.outstandingRequests.Add(validatorID, b.RequestID, vtxID)
		b.needToFetch.Remove(vtxID)
		b.BootstrapConfig.Sender.GetAncestors(validatorID, b.RequestID, vtxID) // request vertex and ancestors
	}
	return b.finish()
}

// Process the vertices in [vtxs].
func (b *bootstrapper) process(vtxs ...avalanche.Vertex) error {
	// Vertices that we need to process. Store them in a heap for de-deduplication
	// and so we always process vertices further down in the DAG first. This helps
	// to reduce the number of repeated DAG traversals.
	toProcess := newMaxVertexHeap()
	for _, vtx := range vtxs {
		if _, ok := b.processedCache.Get(vtx.ID()); !ok { // only process a vertex if we haven't already
			toProcess.Push(vtx)
		}
	}

	for toProcess.Len() > 0 { // While there are unprocessed vertices
		vtx := toProcess.Pop() // Get an unknown vertex or one furthest down the DAG
		vtxID := vtx.ID()

		switch vtx.Status() {
		case choices.Unknown:
			b.needToFetch.Add(vtxID) // We don't have this vertex locally. Mark that we need to fetch it.
		case choices.Rejected:
			b.needToFetch.Remove(vtxID) // We have this vertex locally. Mark that we don't need to fetch it.
			return fmt.Errorf("tried to accept %s even though it was previously rejected", vtx.ID())
		case choices.Processing:
			b.needToFetch.Remove(vtxID)

			if err := b.VtxBlocked.Push(&vertexJob{ // Add to queue of vertices to execute when bootstrapping finishes.
				log:         b.BootstrapConfig.Context.Log,
				numAccepted: b.numBSVtx,
				numDropped:  b.numBSDroppedVtx,
				vtx:         vtx,
			}); err == nil {
				b.numBSBlockedVtx.Inc()
				b.numFetched++ // Progress tracker
				if b.numFetched%common.StatusUpdateFrequency == 0 {
					b.BootstrapConfig.Context.Log.Info("fetched %d vertices", b.numFetched)
				}
			} else {
				b.BootstrapConfig.Context.Log.Verbo("couldn't push to vtxBlocked: %s", err)
			}
			for _, tx := range vtx.Txs() { // Add transactions to queue of transactions to execute when bootstrapping finishes.
				if err := b.TxBlocked.Push(&txJob{
					log:         b.BootstrapConfig.Context.Log,
					numAccepted: b.numBSTx,
					numDropped:  b.numBSDroppedTx,
					tx:          tx,
				}); err == nil {
					b.numBSBlockedTx.Inc()
				} else {
					b.BootstrapConfig.Context.Log.Verbo("couldn't push to txBlocked: %s", err)
				}
			}
			for _, parent := range vtx.Parents() { // Process the parents of this vertex (traverse up the DAG)
				if _, ok := b.processedCache.Get(parent.ID()); !ok { // But only if we haven't processed the parent
					toProcess.Push(parent)
				}
			}
			if vtx.Height()%stripeDistance < stripeWidth { // See comment for stripeDistance
				b.processedCache.Put(vtx.ID(), nil)
			}
		}
	}

	if err := b.VtxBlocked.Commit(); err != nil {
		return err
	}
	if err := b.TxBlocked.Commit(); err != nil {
		return err
	}

	return b.fetch()
}

// MultiPut handles the receipt of multiple containers. Should be received in response to a GetAncestors message to [vdr]
// with request ID [requestID]. Expects vtxs[0] to be the vertex requested in the corresponding GetAncestors.
func (b *bootstrapper) MultiPut(vdr ids.ShortID, requestID uint32, vtxs [][]byte) error {
	if lenVtxs := len(vtxs); lenVtxs > common.MaxContainersPerMultiPut {
		b.BootstrapConfig.Context.Log.Debug("MultiPut(%s, %d) contains more than maximum number of vertices", vdr, requestID)
		return b.GetAncestorsFailed(vdr, requestID)
	} else if lenVtxs == 0 {
		b.BootstrapConfig.Context.Log.Debug("MultiPut(%s, %d) contains no vertices", vdr, requestID)
		return b.GetAncestorsFailed(vdr, requestID)
	}

	// Make sure this is in response to a request we made
	neededVtxID, needed := b.outstandingRequests.Remove(vdr, requestID)
	if !needed { // this message isn't in response to a request we made, or is in response to a request that timed out
		b.BootstrapConfig.Context.Log.Debug("received unexpected MultiPut from %s with ID %d", vdr, requestID)
		return nil
	}

	neededVtx, err := b.State.ParseVertex(vtxs[0]) // first vertex should be the one we requested in GetAncestors request
	if err != nil {
		b.BootstrapConfig.Context.Log.Debug("Failed to parse requested vertex %s: %w", neededVtxID, err)
		b.BootstrapConfig.Context.Log.Verbo("vertex: %s", formatting.DumpBytes{Bytes: vtxs[0]})
		return b.fetch(neededVtxID)
	} else if actualID := neededVtx.ID(); !actualID.Equals(neededVtxID) {
		b.BootstrapConfig.Context.Log.Debug("expected the first block to be the requested block, %s, but is %s", neededVtxID, actualID)
		return b.fetch(neededVtxID)
	}

	processVertices := make([]avalanche.Vertex, 1, len(vtxs)) // Process all of the vertices in this message
	processVertices[0] = neededVtx

	for _, vtxBytes := range vtxs[1:] { // Parse/persist all the vertices
		if vtx, err := b.State.ParseVertex(vtxBytes); err != nil { // Persists the vtx
			b.BootstrapConfig.Context.Log.Debug("Failed to parse vertex: %w", err)
			b.BootstrapConfig.Context.Log.Verbo("vertex: %s", formatting.DumpBytes{Bytes: vtxBytes})
		} else {
			processVertices = append(processVertices, vtx)
			b.needToFetch.Remove(vtx.ID()) // No need to fetch this vertex since we have it now
		}
	}

	return b.process(processVertices...)
}

// GetAncestorsFailed is called when a GetAncestors message we sent fails
func (b *bootstrapper) GetAncestorsFailed(vdr ids.ShortID, requestID uint32) error {
	vtxID, ok := b.outstandingRequests.Remove(vdr, requestID)
	if !ok {
		b.BootstrapConfig.Context.Log.Debug("GetAncestorsFailed(%s, %d) called but there was no outstanding request to this validator with this ID", vdr, requestID)
		return nil
	}
	// Send another request for the vertex
	return b.fetch(vtxID)
}

// ForceAccepted starts bootstrapping. Process the vertices in [accepterContainerIDs].
func (b *bootstrapper) ForceAccepted(acceptedContainerIDs ids.Set) error {
	if err := b.VM.Bootstrapping(); err != nil {
		return fmt.Errorf("failed to notify VM that bootstrapping has started: %w",
			err)
	}

	toProcess := make([]avalanche.Vertex, 0, acceptedContainerIDs.Len())
	for _, vtxID := range acceptedContainerIDs.List() {
		if vtx, err := b.State.GetVertex(vtxID); err == nil {
			toProcess = append(toProcess, vtx) // Process this vertex.
		} else {
			b.needToFetch.Add(vtxID) // We don't have this vertex. Mark that we have to fetch it.
		}
	}
	return b.process(toProcess...)
}

// Finish bootstrapping
func (b *bootstrapper) finish() error {
	// If there are outstanding requests for vertices or we still need to fetch vertices, we can't finish
	if b.finished || b.outstandingRequests.Len() > 0 || b.needToFetch.Len() > 0 {
		return nil
	}

	b.BootstrapConfig.Context.Log.Info("finished fetching %d vertices. executing transaction state transitions...",
		b.numFetched)
	if err := b.executeAll(b.TxBlocked, b.numBSBlockedTx); err != nil {
		return err
	}

	b.BootstrapConfig.Context.Log.Info("executing vertex state transitions...")
	if err := b.executeAll(b.VtxBlocked, b.numBSBlockedVtx); err != nil {
		return err
	}

	if err := b.VM.Bootstrapped(); err != nil {
		return fmt.Errorf("failed to notify VM that bootstrapping has finished: %w",
			err)
	}

	// Start consensus
	if err := b.onFinished(); err != nil {
		return err
	}
	b.finished = true
	return nil
}

func (b *bootstrapper) executeAll(jobs *queue.Jobs, numBlocked prometheus.Gauge) error {
	numExecuted := 0
	for job, err := jobs.Pop(); err == nil; job, err = jobs.Pop() {
		numBlocked.Dec()
		b.BootstrapConfig.Context.Log.Debug("Executing: %s", job.ID())
		if err := jobs.Execute(job); err != nil {
			b.BootstrapConfig.Context.Log.Error("Error executing: %s", err)
			return err
		}
		if err := jobs.Commit(); err != nil {
			return err
		}
		numExecuted++
		if numExecuted%common.StatusUpdateFrequency == 0 { // Periodically print progress
			b.BootstrapConfig.Context.Log.Info("executed %d operations", numExecuted)
		}
	}
	b.BootstrapConfig.Context.Log.Info("executed %d operations", numExecuted)
	return nil
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Contributor:
// - Aaron Meihm ameihm@mozilla.com

package scribe_test

import (
	"fmt"
	"github.com/mozilla/scribe"
	"testing"
)

func TestPackageQuery(t *testing.T) {
	scribe.Bootstrap()
	scribe.TestHooks(true)
	pinfo := scribe.QueryPackages()
	for _, x := range pinfo {
		fmt.Println(x.Name, x.Version, x.Type)
	}
	if len(pinfo) != 7 {
		t.FailNow()
	}
}
<commit_msg>use testing Logf in package tests<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Contributor:
// - Aaron Meihm ameihm@mozilla.com

package scribe_test

import (
	"github.com/mozilla/scribe"
	"testing"
)

func TestPackageQuery(t *testing.T) {
	scribe.Bootstrap()
	scribe.TestHooks(true)
	pinfo := scribe.QueryPackages()
	for _, x := range pinfo {
		t.Logf("%v %v %v", x.Name, x.Version, x.Type)
	}
	if len(pinfo) != 7 {
		t.FailNow()
	}
}
<|endoftext|>


<commit_before>package wordnikext

import (
	"fmt"
	"log"
	"strconv"
	"strings"

	"github.com/ameske/gopherbot/core"
	"github.com/thoj/go-ircevent"
)

var (
	hangmanExtension hangman
)

type hangman struct{}

func (h hangman) Commands() []string {
	return []string{"hangman <guess> - start a new hangman game / take a turn",
		"hangman stats - return player statistics"}
}

func (h hangman) Process(con *irc.Connection, channel string, user string, args []string) {
	if len(args) == 2 && args[1] == "stats" {
		returnStats()
	} else if len(args) == 2 && len(args[1]) == 1 {
		argsLower := strings.ToLower(args[1])
		playHangman(con, channel, user, []byte(argsLower)[0])
	} else {
		con.Privmsg(channel, "That's not a valid hangman command. Did you mean one of these?")
		core.PrintCommands(con, channel, h.Commands())
	}

}

type game struct {
	word     []byte
	correct  []bool
	guesses  []byte
	stats    gameStats
	attempts int
}

func newGame() {
	w, _ := wordnikAPI.RandomDictionaryWordOfLength(5, 12)

	guesses := make([]byte, 0)
	correct := make([]bool, len(w.Word))
	for i, _ := range correct {
		correct[i] = false
	}

	currentGame = &game{
		word:     []byte(strings.ToLower(w.Word)),
		correct:  correct,
		guesses:  guesses,
		stats:    newGameStats(),
		attempts: 8,
	}
}

var (
	currentGame *game
)

func drawGameState() []byte {
	var state []byte

	state = make([]byte, len(currentGame.word))

	for i := 0; i < len(currentGame.word); i++ {
		if currentGame.correct[i] {
			state[i] = currentGame.word[i]
		} else {
			state[i] = '_'
		}
	}

	return state
}

func playHangman(con *irc.Connection, channel string, user string, guess byte) {
	// We don't have a game currently going
	if currentGame == nil {
		newGame()
	}

	if duplicateGuess(guess) {
		con.Privmsg(channel, fmt.Sprintf("You already guessed %c!", int(guess)))
		return
	}

	if !successfulGuess(guess) {
		con.Privmsg(channel, fmt.Sprintf("Sorry, there were no %c's", int(guess)))
		currentGame.attempts--
		return
	}

	switch {
	case won():
		con.Privmsg(channel, fmt.Sprintf("Congrats! You solved the word!"))
		processGame()
	case lost():
		con.Privmsg(channel, fmt.Sprintf("Sorry, you lose! The word was %s", currentGame.word))
		processGame()
	default:
		msg := drawGameState()
		con.Privmsg(channel, string(msg)+fmt.Sprintf(" (%d attempts left)", currentGame.attempts))
	}
}

func duplicateGuess(guess byte) bool {
	for _, ch := range currentGame.guesses {
		if ch == guess {
			return true
		}
	}

	return false
}

func successfulGuess(guess byte) bool {
	currentGame.guesses = append(currentGame.guesses, guess)
	success := false
	for i, ch := range currentGame.word {
		if ch == guess {
			currentGame.correct[i] = true
			success = true
		}
	}

	return success
}

func lost() bool {
	return currentGame.attempts == 0
}

func won() bool {
	for _, c := range currentGame.correct {
		if !c {
			return false
		}
	}

	return true
}

func processGame() {
	prevLetterCount, err := core.Recall("hangman.letters.total")
	if err != nil {
		log.Printf("WARNING: %s", err.Error())
		return
	}

	plcInt, err := strconv.ParseInt(prevLetterCount, 10, 64)
	if err != nil {
		log.Printf("WARNING: %s", err.Error())
		return
	}
	plcInt += int64(len(currentGame.word))

	err = core.Remember("hangman.letters.total", plcInt)
	if err != nil {
		log.Printf("WARNING: %s", err.Error())
		return
	}
}

type gameStats struct {
	total     int
	userStats map[string]int
}

func newGameStats() gameStats {
	return gameStats{
		userStats: make(map[string]int),
	}
}

func returnStats() {
	// TODO - Go to the brain for lifetime stats
}
<commit_msg>Added user letter tracking.<commit_after>package wordnikext

import (
	"fmt"
	"log"
	"strconv"
	"strings"

	"github.com/ameske/gopherbot/core"
	"github.com/thoj/go-ircevent"
)

var (
	hangmanExtension hangman
)

type hangman struct{}

func (h hangman) Commands() []string {
	return []string{"hangman <guess> - start a new hangman game / take a turn",
		"hangman stats - return player statistics"}
}

func (h hangman) Process(con *irc.Connection, channel string, user string, args []string) {
	if len(args) == 2 && args[1] == "stats" {
		returnStats(con, channel)
	} else if len(args) == 2 && len(args[1]) == 1 {
		argsLower := strings.ToLower(args[1])
		playHangman(con, channel, user, []byte(argsLower)[0])
	} else {
		con.Privmsg(channel, "That's not a valid hangman command. Did you mean one of these?")
		core.PrintCommands(con, channel, h.Commands())
	}

}

type game struct {
	word      []byte
	correct   []bool
	guesses   []byte
	userStats map[string]int
	attempts  int
}

func newGame() {
	w, _ := wordnikAPI.RandomDictionaryWordOfLength(5, 12)

	currentGame = &game{
		word:      []byte(strings.ToLower(w.Word)),
		correct:   make([]bool, len(w.Word)),
		guesses:   make([]byte, 0),
		userStats: make(map[string]int),
		attempts:  8,
	}
}

var (
	currentGame *game
)

func drawGameState() []byte {
	var state []byte

	state = make([]byte, len(currentGame.word))

	for i := 0; i < len(currentGame.word); i++ {
		if currentGame.correct[i] {
			state[i] = currentGame.word[i]
		} else {
			state[i] = '_'
		}
	}

	return state
}

func playHangman(con *irc.Connection, channel string, user string, guess byte) {
	// We don't have a game currently going
	if currentGame == nil {
		newGame()
	}

	if duplicateGuess(guess) {
		con.Privmsg(channel, fmt.Sprintf("You already guessed %c!", int(guess)))
		return
	}

	if !successfulGuess(guess) {
		con.Privmsg(channel, fmt.Sprintf("Sorry, there were no %c's", int(guess)))
		currentGame.attempts--
		return
	}

	currentGame.userStats[user] = currentGame.userStats[user] + 1

	switch {
	case won():
		con.Privmsg(channel, fmt.Sprintf("Congrats! You solved the word!"))
		updateStats()
	case lost():
		con.Privmsg(channel, fmt.Sprintf("Sorry, you lose! The word was %s", currentGame.word))
		updateStats()
	default:
		msg := drawGameState()
		con.Privmsg(channel, string(msg)+fmt.Sprintf(" (%d attempts left)", currentGame.attempts))
	}
}

func duplicateGuess(guess byte) bool {
	for _, ch := range currentGame.guesses {
		if ch == guess {
			return true
		}
	}

	return false
}

func successfulGuess(guess byte) bool {
	currentGame.guesses = append(currentGame.guesses, guess)
	success := false
	for i, ch := range currentGame.word {
		if ch == guess {
			currentGame.correct[i] = true
			success = true
		}
	}

	return success
}

func lost() bool {
	return currentGame.attempts == 0
}

func won() bool {
	for _, c := range currentGame.correct {
		if !c {
			return false
		}
	}

	return true
}

func updateStats() {
	prevLetterCount, err := core.Recall("hangman.letters.total")
	if err != nil {
		prevLetterCount = "0"
	}

	plcInt, err := strconv.ParseInt(prevLetterCount, 10, 64)
	if err != nil {
		log.Printf("WARNING: %s", err.Error())
		return
	}
	plcInt += int64(len(currentGame.word))

	err = core.Remember("hangman.letters.total", plcInt)
	if err != nil {
		log.Printf("WARNING: %s", err.Error())
		return
	}

	for k, v := range currentGame.userStats {
		prevUserLetterCount, err := core.RecallHash("hangman.letters.user", k)
		if err != nil {
			prevUserLetterCount = "0"
		}

		pulcInt, err := strconv.ParseInt(prevUserLetterCount, 10, 64)
		if err != nil {
			log.Printf("WARNING: %s", err.Error())
			return
		}
		pulcInt += int64(v)

		err = core.RememberHash("hangman.letters.user", k, pulcInt)
		if err != nil {
			log.Printf("WARNING: %s", err.Error())
			return
		}
	}
}

func returnStats(con *irc.Connection, channel string) {
	totalLetters, err := core.Recall("hangman.letters.total")
	if err != nil {
		log.Printf("WARNING: %s", err.Error())
		con.Privmsg(channel, "Sorry, I couldn't retrieve stats at the moment")
		return
	}

	tlInt, err := strconv.ParseInt(totalLetters, 10, 64)
	if err != nil {
		log.Printf("WARNING: %s", err.Error())
		return
	}

	players, err := core.RecallHashAll("hangman.letters.user")
	if err != nil {
		log.Printf("WARNING: %s", err.Error())
		con.Privmsg(channel, "Sorry, I couldn't retrieve stats at the moment")
		return
	}

	con.Privmsg(channel, fmt.Sprintf("Total Letters: %d", tlInt))
	for i := 0; i < len(players); i += 2 {
		uInt, err := strconv.ParseInt(players[i+1], 10, 64)
		if err != nil {
			log.Printf("WARNING: %s", err.Error())
			return
		}
		con.Privmsg(channel, fmt.Sprintf("\t%s: %d letters", players[i], uInt))
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

package libdokan

import (
	"time"

	"github.com/keybase/kbfs/dokan"
	"github.com/keybase/kbfs/dokan/winacl"
	"golang.org/x/net/context"
)

// Return dokan.ErrAccessDenied by default as that is a safe default.

type emptyFile struct{}

func (t emptyFile) Cleanup(ctx context.Context, fi *dokan.FileInfo) {
}
func (t emptyFile) CloseFile(ctx context.Context, fi *dokan.FileInfo) {
}
func (t emptyFile) SetEndOfFile(ctx context.Context, fi *dokan.FileInfo, length int64) error {
	return dokan.ErrAccessDenied
}
func (t emptyFile) SetAllocationSize(ctx context.Context, fi *dokan.FileInfo, length int64) error {
	return dokan.ErrAccessDenied
}
func (t emptyFile) ReadFile(ctx context.Context, fi *dokan.FileInfo, bs []byte, offset int64) (int, error) {
	return 0, dokan.ErrAccessDenied
}
func (t emptyFile) WriteFile(ctx context.Context, fi *dokan.FileInfo, bs []byte, offset int64) (int, error) {
	return 0, dokan.ErrAccessDenied
}
func (t emptyFile) FlushFileBuffers(ctx context.Context, fi *dokan.FileInfo) error {
	return dokan.ErrAccessDenied
}
func (t emptyFile) FindFiles(ctx context.Context, fi *dokan.FileInfo, ignored string, cb func(*dokan.NamedStat) error) error {
	return dokan.ErrAccessDenied
}
func (t emptyFile) SetFileTime(context.Context, *dokan.FileInfo, time.Time, time.Time, time.Time) error {
	return dokan.ErrAccessDenied
}
func (t emptyFile) SetFileAttributes(ctx context.Context, fi *dokan.FileInfo, fileAttributes dokan.FileAttribute) error {
	return dokan.ErrAccessDenied
}
func (t emptyFile) LockFile(ctx context.Context, fi *dokan.FileInfo, offset int64, length int64) error {
	return dokan.ErrAccessDenied
}
func (t emptyFile) UnlockFile(ctx context.Context, fi *dokan.FileInfo, offset int64, length int64) error {
	return dokan.ErrAccessDenied
}
func (t emptyFile) CanDeleteFile(ctx context.Context, fi *dokan.FileInfo) error {
	return dokan.ErrAccessDenied
}
func (t emptyFile) CanDeleteDirectory(ctx context.Context, fi *dokan.FileInfo) error {
	return dokan.ErrAccessDenied
}
func (t emptyFile) GetFileSecurity(ctx context.Context, fi *dokan.FileInfo, si winacl.SecurityInformation, sd *winacl.SecurityDescriptor) error {
	if si&winacl.OwnerSecurityInformation != 0 && currentUserSID != nil {
		sd.SetOwner(currentUserSID)
	}
	if si&winacl.GroupSecurityInformation != 0 && currentGroupSID != nil {
		sd.SetGroup(currentGroupSID)
	}
	return nil
}
func (t emptyFile) SetFileSecurity(ctx context.Context, fi *dokan.FileInfo, si winacl.SecurityInformation, sd *winacl.SecurityDescriptor) error {
	return dokan.ErrAccessDenied
}
<commit_msg>libdokan: Simple DACL support<commit_after>// Copyright 2016 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

package libdokan

import (
	"time"

	"github.com/keybase/kbfs/dokan"
	"github.com/keybase/kbfs/dokan/winacl"
	"golang.org/x/net/context"
)

// Return dokan.ErrAccessDenied by default as that is a safe default.

type emptyFile struct{}

func (t emptyFile) Cleanup(ctx context.Context, fi *dokan.FileInfo) {
}
func (t emptyFile) CloseFile(ctx context.Context, fi *dokan.FileInfo) {
}
func (t emptyFile) SetEndOfFile(ctx context.Context, fi *dokan.FileInfo, length int64) error {
	return dokan.ErrAccessDenied
}
func (t emptyFile) SetAllocationSize(ctx context.Context, fi *dokan.FileInfo, length int64) error {
	return dokan.ErrAccessDenied
}
func (t emptyFile) ReadFile(ctx context.Context, fi *dokan.FileInfo, bs []byte, offset int64) (int, error) {
	return 0, dokan.ErrAccessDenied
}
func (t emptyFile) WriteFile(ctx context.Context, fi *dokan.FileInfo, bs []byte, offset int64) (int, error) {
	return 0, dokan.ErrAccessDenied
}
func (t emptyFile) FlushFileBuffers(ctx context.Context, fi *dokan.FileInfo) error {
	return dokan.ErrAccessDenied
}
func (t emptyFile) FindFiles(ctx context.Context, fi *dokan.FileInfo, ignored string, cb func(*dokan.NamedStat) error) error {
	return dokan.ErrAccessDenied
}
func (t emptyFile) SetFileTime(context.Context, *dokan.FileInfo, time.Time, time.Time, time.Time) error {
	return dokan.ErrAccessDenied
}
func (t emptyFile) SetFileAttributes(ctx context.Context, fi *dokan.FileInfo, fileAttributes dokan.FileAttribute) error {
	return dokan.ErrAccessDenied
}
func (t emptyFile) LockFile(ctx context.Context, fi *dokan.FileInfo, offset int64, length int64) error {
	return dokan.ErrAccessDenied
}
func (t emptyFile) UnlockFile(ctx context.Context, fi *dokan.FileInfo, offset int64, length int64) error {
	return dokan.ErrAccessDenied
}
func (t emptyFile) CanDeleteFile(ctx context.Context, fi *dokan.FileInfo) error {
	return dokan.ErrAccessDenied
}
func (t emptyFile) CanDeleteDirectory(ctx context.Context, fi *dokan.FileInfo) error {
	return dokan.ErrAccessDenied
}
func (t emptyFile) GetFileSecurity(ctx context.Context, fi *dokan.FileInfo, si winacl.SecurityInformation, sd *winacl.SecurityDescriptor) error {
	if si&winacl.OwnerSecurityInformation != 0 && currentUserSID != nil {
		sd.SetOwner(currentUserSID)
	}
	if si&winacl.GroupSecurityInformation != 0 && currentGroupSID != nil {
		sd.SetGroup(currentGroupSID)
	}
	if si&winacl.DACLSecurityInformation != 0 {
		var acl winacl.Acl
		acl.AddAllowAccess(0x001F01FF, currentUserSID)
		sd.SetDacl(&acl)
	}
	return nil
}
func (t emptyFile) SetFileSecurity(ctx context.Context, fi *dokan.FileInfo, si winacl.SecurityInformation, sd *winacl.SecurityDescriptor) error {
	return dokan.ErrAccessDenied
}
<|endoftext|>


<commit_before>package app

import (
	"errors"
	"fmt"
	"log"
	"strings"

	"github.com/julwrites/BotPlatform/pkg/def"
)

const (
	MCBRP string = "MCBRP"
	DJBRP string = "DJBRP"
	DGORG string = "DGORG"
)

var DEVOS = map[string]string{
	"M'Cheyne Bible Reading Plan":             MCBRP,
	"Discipleship Journal Bible Reading Plan": DJBRP,
	"Desiring God Articles":                   DGORG,
}

func SanitizeDevo(msg string) (string, error) {
	msg = strings.Trim(msg, " ")
	devo, ok := DEVOS[msg]
	if ok {
		return devo, nil
	}
	return "", errors.New(fmt.Sprintf("Devo could not be recognized %s", msg))
}

func GetDevotionalText(devo string) string {
	var text string

	switch devo {
	case MCBRP:
		fallthrough
	case DJBRP:
		text = "Here are today's Bible Reading passages, tap on any one to get the passage!"
		break
	case DGORG:
		text = "Here are today's DesiringGod.org articles, tap on any one to open the article!"
		break
	}

	return text
}

func GetDevotionalData(env def.SessionData, devo string) def.ResponseData {
	var response def.ResponseData

	response.Message = GetDevotionalText(devo)

	switch devo {
	case MCBRP:
		response.Affordances.Options = GetMCheyneReferences()
		response.Affordances.Options = append(response.Affordances.Options, def.Option{Text: CMD_CLOSE})
		break
	case DJBRP:
		response.Affordances.Options = GetDiscipleshipJournalReferences(env)
		if len(response.Affordances.Options) == 0 {
			response.Message = "Take this time today to reflect over this week's devotions"
		} else {
			response.Affordances.Options = append(response.Affordances.Options, def.Option{Text: CMD_CLOSE})
		}
		break
	case DGORG:
		response.Affordances.Options = GetDesiringGodArticles()
		response.Affordances.Inline = true
		break
	default:
		response.Affordances.Remove = true
		break
	}

	return response
}

func GetDevo(env def.SessionData) def.SessionData {
	switch env.User.Action {
	case CMD_DEVO:
		log.Printf("Detected existing action /devo")

		devo, err := SanitizeDevo(env.Msg.Message)
		if err == nil {
			log.Printf("Devotional is valid, retrieving %s", devo)

			// Retrieve devotional
			env.Res = GetDevotionalData(env, devo)

			env.User.Action = ""
		} else {
			log.Printf("SanitizeDevo failed %v", err)
			env.Res.Message = "I didn't recognize that devo, please try again"
		}

		break
	default:
		log.Printf("Activating action /devo")

		var options []def.Option

		for k, _ := range DEVOS {
			options = append(options, def.Option{Text: k})
		}
		options = append(options, def.Option{Text: CMD_CLOSE})

		env.Res.Affordances.Options = options

		env.User.Action = CMD_DEVO

		env.Res.Message = "Choose a Devotional to read!"

		break
	}

	return env
}
<commit_msg>Allowing an early PostFromProps to occur in Devo to improve user experience<commit_after>package app

import (
	"errors"
	"fmt"
	"log"
	"strings"

	"github.com/julwrites/BotPlatform/pkg/platform"

	"github.com/julwrites/BotPlatform/pkg/def"
)

const (
	MCBRP string = "MCBRP"
	DJBRP string = "DJBRP"
	DGORG string = "DGORG"
)

var DEVOS = map[string]string{
	"M'Cheyne Bible Reading Plan":             MCBRP,
	"Discipleship Journal Bible Reading Plan": DJBRP,
	"Desiring God Articles":                   DGORG,
}

func SanitizeDevo(msg string) (string, error) {
	msg = strings.Trim(msg, " ")
	devo, ok := DEVOS[msg]
	if ok {
		return devo, nil
	}
	return "", errors.New(fmt.Sprintf("Devo could not be recognized %s", msg))
}

func GetDevotionalText(devo string) string {
	var text string

	switch devo {
	case MCBRP:
		fallthrough
	case DJBRP:
		text = "Here are today's Bible Reading passages, tap on any one to get the passage!"
		break
	case DGORG:
		text = "Here are today's DesiringGod.org articles, tap on any one to open the article!"
		break
	}

	return text
}

func GetDevotionalData(env def.SessionData, devo string) def.ResponseData {
	var response def.ResponseData

	response.Message = GetDevotionalText(devo)

	switch devo {
	case MCBRP:
		response.Affordances.Options = GetMCheyneReferences()
		response.Affordances.Options = append(response.Affordances.Options, def.Option{Text: CMD_CLOSE})
		break
	case DJBRP:
		response.Affordances.Options = GetDiscipleshipJournalReferences(env)
		if len(response.Affordances.Options) == 0 {
			response.Message = "Take this time today to reflect over this week's devotions"
		} else {
			response.Affordances.Options = append(response.Affordances.Options, def.Option{Text: CMD_CLOSE})
		}
		break
	case DGORG:
		response.Affordances.Options = GetDesiringGodArticles()
		response.Affordances.Inline = true
		break
	default:
		response.Affordances.Remove = true
		break
	}

	return response
}

func GetDevo(env def.SessionData) def.SessionData {
	switch env.User.Action {
	case CMD_DEVO:
		log.Printf("Detected existing action /devo")

		devo, err := SanitizeDevo(env.Msg.Message)
		if err == nil {
			log.Printf("Devotional is valid, retrieving %s", devo)

			env.Res.Affordances.Remove = true
			env.Res.Message = "Just a moment..."

			platform.PostFromProps(env)

			// Retrieve devotional
			env.Res = GetDevotionalData(env, devo)

			env.User.Action = ""
		} else {
			log.Printf("SanitizeDevo failed %v", err)
			env.Res.Message = "I didn't recognize that devo, please try again"
		}

		break
	default:
		log.Printf("Activating action /devo")

		var options []def.Option

		for k, _ := range DEVOS {
			options = append(options, def.Option{Text: k})
		}
		options = append(options, def.Option{Text: CMD_CLOSE})

		env.Res.Affordances.Options = options

		env.User.Action = CMD_DEVO

		env.Res.Message = "Choose a Devotional to read!"

		break
	}

	return env
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	log "github.com/Sirupsen/logrus"
	"github.com/matt-deboer/etcdcd/pkg/discovery"
	_ "github.com/matt-deboer/etcdcd/pkg/platform/all"
	"github.com/urfave/cli"
)

// Name is set at compile time based on the git repository
var Name string

// Version is set at compile time with the git version
var Version string

func main() {

	app := cli.NewApp()
	app.Name = Name
	app.Usage = `etcdcd

		Dynamically discover etcd cluster membership for a specific platform
		`
	app.Version = Version
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "platform",
			Usage:  "The platform",
			EnvVar: "ETCDCD_PLATFORM",
		},
		cli.StringFlag{
			Name:   "platform-config-file, c",
			Usage:  "The platform config file",
			EnvVar: "ETCDCD_PLATFORM_CONFIG",
		},
		cli.IntFlag{
			Name:   "client-port",
			Value:  2379,
			Usage:  "The port advertised for etcd client access",
			EnvVar: "ETCDCD_CLIENT_PORT",
		},
		cli.IntFlag{
			Name:   "server-port",
			Value:  2380,
			Usage:  "The port advertised for etcd client access",
			EnvVar: "ETCDCD_SERVER_PORT",
		},
		cli.StringFlag{
			Name:   "client-scheme",
			Value:  "http",
			Usage:  "The scheme for etcd client access urls",
			EnvVar: "ETCDCD_CLIENT_SCHEME",
		},
		cli.StringFlag{
			Name:   "server-scheme",
			Value:  "http",
			Usage:  "The scheme for etcd server access urls",
			EnvVar: "ETCDCD_SERVER_SCHEME",
		},
		cli.BoolFlag{
			Name:   "proxy",
			Usage:  "Whether to enable proxy mode",
			EnvVar: "ETCDCD_PROXY_MODE",
		},
		cli.StringFlag{
			Name:   "master-name-filter",
			Usage:  "Masters' names will contain this string",
			EnvVar: "ETCDCD_MASTER_NAME_FILTER",
		},
		cli.BoolFlag{
			Name:   "dry-run",
			Usage:  "Don't perform any changes; instead log what would have been done",
			EnvVar: "ETCDCD_DRY_RUN",
		},
		cli.BoolFlag{
			Name:   "verbose, V",
			Usage:  "Log extra information about steps taken",
			EnvVar: "ETCDCD_VERBOSE",
		},
		cli.StringFlag{
			Name:   "client-cert-file",
			Usage:  "Client certificate to use when client-scheme is 'https'",
			EnvVar: "ETCDCD_CLIENT_CERT_FILE",
		},
	}
	app.Action = func(c *cli.Context) {

		if c.Bool("verbose") {
			log.SetLevel(log.DebugLevel)
		}
		environment, err := parseArgs(c).DiscoverEnvironment()
		if err != nil {
			log.Fatalf("Environment discovery failed; %v", err)
		}
		for k, v := range environment {
			println(fmt.Sprintf(`%s="%s"`, k, v))
		}
	}
	app.Run(os.Args)

}

func parseArgs(c *cli.Context) *discovery.Discovery {

	platform := c.String("platform")
	if len(platform) == 0 {
		log.Fatalf("'%s' is required", "platform")
	}
	masterFilter := c.String("master-name-filter")
	if len(masterFilter) == 0 {
		log.Fatalf("'%s' is required", "master-name-filter")
	}

	return &discovery.Discovery{
		Platform:     platform,
		ConfigFile:   c.String("platform-config-file"),
		ClientPort:   c.Int("client-port"),
		ServerPort:   c.Int("server-port"),
		ClientScheme: c.String("client-scheme"),
		ServerScheme: c.String("server-scheme"),
		ProxyMode:    c.Bool("proxy"),
		MasterFilter: masterFilter,
	}
}
<commit_msg>write results to stdout<commit_after>package main

import (
	"fmt"
	"os"

	log "github.com/Sirupsen/logrus"
	"github.com/matt-deboer/etcdcd/pkg/discovery"
	_ "github.com/matt-deboer/etcdcd/pkg/platform/all"
	"github.com/urfave/cli"
)

// Name is set at compile time based on the git repository
var Name string

// Version is set at compile time with the git version
var Version string

func main() {

	app := cli.NewApp()
	app.Name = Name
	app.Usage = `etcdcd

		Dynamically discover etcd cluster membership for a specific platform
		`
	app.Version = Version
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "platform",
			Usage:  "The platform",
			EnvVar: "ETCDCD_PLATFORM",
		},
		cli.StringFlag{
			Name:   "platform-config-file, c",
			Usage:  "The platform config file",
			EnvVar: "ETCDCD_PLATFORM_CONFIG",
		},
		cli.IntFlag{
			Name:   "client-port",
			Value:  2379,
			Usage:  "The port advertised for etcd client access",
			EnvVar: "ETCDCD_CLIENT_PORT",
		},
		cli.IntFlag{
			Name:   "server-port",
			Value:  2380,
			Usage:  "The port advertised for etcd client access",
			EnvVar: "ETCDCD_SERVER_PORT",
		},
		cli.StringFlag{
			Name:   "client-scheme",
			Value:  "http",
			Usage:  "The scheme for etcd client access urls",
			EnvVar: "ETCDCD_CLIENT_SCHEME",
		},
		cli.StringFlag{
			Name:   "server-scheme",
			Value:  "http",
			Usage:  "The scheme for etcd server access urls",
			EnvVar: "ETCDCD_SERVER_SCHEME",
		},
		cli.BoolFlag{
			Name:   "proxy",
			Usage:  "Whether to enable proxy mode",
			EnvVar: "ETCDCD_PROXY_MODE",
		},
		cli.StringFlag{
			Name:   "master-name-filter",
			Usage:  "Masters' names will contain this string",
			EnvVar: "ETCDCD_MASTER_NAME_FILTER",
		},
		cli.BoolFlag{
			Name:   "dry-run",
			Usage:  "Don't perform any changes; instead log what would have been done",
			EnvVar: "ETCDCD_DRY_RUN",
		},
		cli.BoolFlag{
			Name:   "verbose, V",
			Usage:  "Log extra information about steps taken",
			EnvVar: "ETCDCD_VERBOSE",
		},
		cli.StringFlag{
			Name:   "client-cert-file",
			Usage:  "Client certificate to use when client-scheme is 'https'",
			EnvVar: "ETCDCD_CLIENT_CERT_FILE",
		},
	}
	app.Action = func(c *cli.Context) {

		if c.Bool("verbose") {
			log.SetLevel(log.DebugLevel)
		}
		environment, err := parseArgs(c).DiscoverEnvironment()
		if err != nil {
			log.Fatalf("Environment discovery failed; %v", err)
		}
		for k, v := range environment {
			fmt.Printf(`%s="%s"`, k, v)
		}
	}
	app.Run(os.Args)

}

func parseArgs(c *cli.Context) *discovery.Discovery {

	platform := c.String("platform")
	if len(platform) == 0 {
		log.Fatalf("'%s' is required", "platform")
	}
	masterFilter := c.String("master-name-filter")
	if len(masterFilter) == 0 {
		log.Fatalf("'%s' is required", "master-name-filter")
	}

	return &discovery.Discovery{
		Platform:     platform,
		ConfigFile:   c.String("platform-config-file"),
		ClientPort:   c.Int("client-port"),
		ServerPort:   c.Int("server-port"),
		ClientScheme: c.String("client-scheme"),
		ServerScheme: c.String("server-scheme"),
		ProxyMode:    c.Bool("proxy"),
		MasterFilter: masterFilter,
	}
}
<|endoftext|>


<commit_before>// Copyright 2021 Authors of Cilium
//
// 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 ebpf

import (
	"fmt"

	"github.com/cilium/cilium/api/v1/models"
	"github.com/cilium/cilium/pkg/bpf"
	"github.com/cilium/cilium/pkg/lock"

	ciliumebpf "github.com/cilium/ebpf"
)

type MapSpec = ciliumebpf.MapSpec

const (
	PerCPUHash = ciliumebpf.PerCPUHash

	PinByName = ciliumebpf.PinByName
)

// IterateCallback represents the signature of the callback function expected by
// the IterateWithCallback method, which in turn is used to iterate all the
// keys/values of a map.
type IterateCallback func(key, value interface{})

// Map represents an eBPF map.
type Map struct {
	lock lock.RWMutex
	*ciliumebpf.Map

	spec *MapSpec
	path string
}

// NewMap creates a new Map object.
func NewMap(spec *MapSpec) *Map {
	return &Map{
		spec: spec,
	}
}

// OpenOrCreate tries to open or create the eBPF map identified by the spec in
// the Map object.
func (m *Map) OpenOrCreate() error {
	m.lock.Lock()
	defer m.lock.Unlock()

	if m.Map != nil {
		return nil
	}

	opts := ciliumebpf.MapOptions{
		PinPath: bpf.MapPrefixPath(),
	}

	newMap, err := ciliumebpf.NewMapWithOptions(m.spec, opts)
	if err != nil {
		return fmt.Errorf("unable to create map: %w", err)
	}

	m.Map = newMap
	m.path = bpf.MapPath(m.spec.Name)

	registerMap(m)
	return nil
}

// IterateWithCallback iterates through all the keys/values of a map, passing
// each key/value pair to the cb callback.
func (m *Map) IterateWithCallback(key, value interface{}, cb IterateCallback) error {
	if m.Map == nil {
		if err := m.OpenOrCreate(); err != nil {
			return err
		}
	}

	m.lock.RLock()
	defer m.lock.RUnlock()

	entries := m.Iterate()
	for entries.Next(key, value) {
		cb(key, value)
	}

	return nil
}

// GetModel returns a BPF map in the representation served via the API.
func (m *Map) GetModel() *models.BPFMap {
	m.lock.RLock()
	defer m.lock.RUnlock()

	mapModel := &models.BPFMap{
		Path: m.path,
	}

	// TODO: handle map cache. See pkg/bpf/map_linux.go:GetModel()

	return mapModel
}
<commit_msg>ebpf: Add missing map preallocate flags<commit_after>// Copyright 2021 Authors of Cilium
//
// 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 ebpf

import (
	"fmt"

	"github.com/cilium/cilium/api/v1/models"
	"github.com/cilium/cilium/pkg/bpf"
	"github.com/cilium/cilium/pkg/lock"

	ciliumebpf "github.com/cilium/ebpf"
)

type MapSpec = ciliumebpf.MapSpec

const (
	PerCPUHash = ciliumebpf.PerCPUHash

	PinByName = ciliumebpf.PinByName
)

// IterateCallback represents the signature of the callback function expected by
// the IterateWithCallback method, which in turn is used to iterate all the
// keys/values of a map.
type IterateCallback func(key, value interface{})

// Map represents an eBPF map.
type Map struct {
	lock lock.RWMutex
	*ciliumebpf.Map

	spec *MapSpec
	path string
}

// NewMap creates a new Map object.
func NewMap(spec *MapSpec) *Map {
	return &Map{
		spec: spec,
	}
}

// OpenOrCreate tries to open or create the eBPF map identified by the spec in
// the Map object.
func (m *Map) OpenOrCreate() error {
	m.lock.Lock()
	defer m.lock.Unlock()

	if m.Map != nil {
		return nil
	}

	opts := ciliumebpf.MapOptions{
		PinPath: bpf.MapPrefixPath(),
	}

	mapType := bpf.GetMapType(bpf.MapType(m.spec.Type))
	m.spec.Flags = m.spec.Flags | bpf.GetPreAllocateMapFlags(mapType)

	newMap, err := ciliumebpf.NewMapWithOptions(m.spec, opts)
	if err != nil {
		return fmt.Errorf("unable to create map: %w", err)
	}

	m.Map = newMap
	m.path = bpf.MapPath(m.spec.Name)

	registerMap(m)
	return nil
}

// IterateWithCallback iterates through all the keys/values of a map, passing
// each key/value pair to the cb callback.
func (m *Map) IterateWithCallback(key, value interface{}, cb IterateCallback) error {
	if m.Map == nil {
		if err := m.OpenOrCreate(); err != nil {
			return err
		}
	}

	m.lock.RLock()
	defer m.lock.RUnlock()

	entries := m.Iterate()
	for entries.Next(key, value) {
		cb(key, value)
	}

	return nil
}

// GetModel returns a BPF map in the representation served via the API.
func (m *Map) GetModel() *models.BPFMap {
	m.lock.RLock()
	defer m.lock.RUnlock()

	mapModel := &models.BPFMap{
		Path: m.path,
	}

	// TODO: handle map cache. See pkg/bpf/map_linux.go:GetModel()

	return mapModel
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The Knative 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 k8s

import (
	"context"
	"fmt"
	"log"
	"time"

	"github.com/pkg/errors"
	corev1 "k8s.io/api/core/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/util/wait"
	"knative.dev/pkg/apis"
	duckv1 "knative.dev/pkg/apis/duck/v1"
	kubeclient "knative.dev/pkg/client/injection/kube/client"
	"knative.dev/pkg/injection/clients/dynamicclient"
	pkgtest "knative.dev/pkg/test"

	"knative.dev/reconciler-test/pkg/environment"
	"knative.dev/reconciler-test/pkg/feature"
)

// PollTimings will find the the correct timings based on priority:
// - passed timing slice [interval, timeout].
// - values from from context.
// - defaults.
func PollTimings(ctx context.Context, timings []time.Duration) (time.Duration /*interval*/, time.Duration /*timeout*/) {
	// Use the passed timing first, but it could be nil or a strange length.
	if len(timings) >= 2 {
		return timings[0], timings[1]
	}

	var interval *time.Duration

	// Use the passed timings if only interval is provided.
	if len(timings) == 1 {
		interval = &timings[0]
	}

	di, timeout := environment.PollTimingsFromContext(ctx)
	if interval == nil {
		interval = &di
	}

	return *interval, timeout
}

// WaitForReadyOrDone will wait for a resource to become ready or succeed.
// Timing is optional but if provided is [interval, timeout].
func WaitForReadyOrDone(ctx context.Context, ref corev1.ObjectReference, timing ...time.Duration) error {
	interval, timeout := PollTimings(ctx, timing)

	k := ref.GroupVersionKind()
	gvr, _ := meta.UnsafeGuessKindToResource(k)

	switch gvr.Resource {
	case "jobs":
		err := WaitUntilJobDone(ctx, kubeclient.Get(ctx), ref.Namespace, ref.Name, interval, timeout)
		if err != nil {
			return err
		}
		return nil

	default:
		err := WaitForResourceReady(ctx, ref.Namespace, ref.Name, gvr, interval, timeout)
		if err != nil {
			return err
		}
	}

	return nil
}

// WaitForResourceReady waits until the specified resource in the given namespace are ready.
// Timing is optional but if provided is [interval, timeout].
func WaitForResourceReady(ctx context.Context, namespace, name string, gvr schema.GroupVersionResource, timing ...time.Duration) error {
	interval, timeout := PollTimings(ctx, timing)

	lastMsg := ""
	like := &duckv1.KResource{}
	return wait.PollImmediate(interval, timeout, func() (bool, error) {
		client := dynamicclient.Get(ctx)

		us, err := client.Resource(gvr).Namespace(namespace).Get(ctx, name, metav1.GetOptions{})
		if err != nil {
			if apierrors.IsNotFound(err) {
				log.Println(namespace, name, "not found", err)
				// keep polling
				return false, nil
			}
			return false, err
		}
		obj := like.DeepCopy()
		if err = runtime.DefaultUnstructuredConverter.FromUnstructured(us.Object, obj); err != nil {
			log.Fatalf("Error DefaultUnstructuree.Dynamiconverter. %v", err)
		}
		obj.ResourceVersion = gvr.Version
		obj.APIVersion = gvr.GroupVersion().String()

		// First see if the resource has conditions.
		if len(obj.Status.Conditions) == 0 {
			return false, nil // keep polling
		}

		// Ready type.
		ready := obj.Status.GetCondition(apis.ConditionReady)
		if ready != nil {
			// Succeeded type.
			ready = obj.Status.GetCondition(apis.ConditionSucceeded)
		}
		// Test Ready or Succeeded.
		if ready != nil {
			if !ready.IsTrue() {
				msg := fmt.Sprintf("%s is not %s, %s: %s", name, ready.Type, ready.Reason, ready.Message)
				if msg != lastMsg {
					log.Println(msg)
					lastMsg = msg
				}
			}

			log.Printf("%s is %s, %s: %s\n", name, ready.Type, ready.Reason, ready.Message)
			return ready.IsTrue(), nil
		}

		// Last resort, look at all conditions.
		// As a side-effect of this test,
		//   if a resource has no conditions, then it is ready.
		allReady := true
		for _, c := range obj.Status.Conditions {
			if !c.IsTrue() {
				msg := fmt.Sprintf("%s is not %s, %s: %s", name, c.Type, c.Reason, c.Message)
				if msg != lastMsg {
					log.Println(msg)
					lastMsg = msg
				}
				allReady = false
				break
			}
		}
		return allReady, nil
	})
}

// WaitForServiceEndpointsOrFail wraps the utility from pkg and uses the context to extract kubeclient and namespace
func WaitForServiceEndpointsOrFail(ctx context.Context, t feature.T, svcName string, numberOfExpectedEndpoints int) {
	if err := pkgtest.WaitForServiceEndpoints(ctx, kubeclient.Get(ctx), svcName, environment.FromContext(ctx).Namespace(), numberOfExpectedEndpoints); err != nil {
		t.Fatalf("Failed while waiting for %d endpoints in service %s: %+v", numberOfExpectedEndpoints, svcName, errors.WithStack(err))
	}
}

// WaitForPodRunningOrFail wraps the utility from pkg and uses the context to extract kubeclient and namespace
func WaitForPodRunningOrFail(ctx context.Context, t feature.T, podName string) {
	if err := pkgtest.WaitForPodRunning(ctx, kubeclient.Get(ctx), podName, environment.FromContext(ctx).Namespace()); err != nil {
		t.Fatalf("Failed while waiting for pod %s running: %+v", podName, errors.WithStack(err))
	}
}

// WaitForAddress waits until a resource has an address.
// Timing is optional but if provided is [interval, timeout].
func WaitForAddress(ctx context.Context, gvr schema.GroupVersionResource, name string, timing ...time.Duration) (*apis.URL, error) {
	interval, timeout := PollTimings(ctx, timing)

	var addr *apis.URL
	err := wait.PollImmediate(interval, timeout, func() (bool, error) {
		var err error
		addr, err = Address(ctx, gvr, name)
		if err == nil && addr == nil {
			// keep polling
			return false, nil
		}
		if err != nil {
			if apierrors.IsNotFound(err) {
				// keep polling
				return false, nil
			}
			// seems fatal.
			return false, err
		}
		// success!
		return true, nil
	})
	return addr, err
}
<commit_msg>add debug to failed start pods (#170)<commit_after>/*
Copyright 2020 The Knative 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 k8s

import (
	"context"
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/pkg/errors"
	corev1 "k8s.io/api/core/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/util/wait"
	"knative.dev/pkg/apis"
	duckv1 "knative.dev/pkg/apis/duck/v1"
	kubeclient "knative.dev/pkg/client/injection/kube/client"
	"knative.dev/pkg/injection/clients/dynamicclient"
	pkgtest "knative.dev/pkg/test"

	"knative.dev/reconciler-test/pkg/environment"
	"knative.dev/reconciler-test/pkg/feature"
)

// PollTimings will find the the correct timings based on priority:
// - passed timing slice [interval, timeout].
// - values from from context.
// - defaults.
func PollTimings(ctx context.Context, timings []time.Duration) (time.Duration /*interval*/, time.Duration /*timeout*/) {
	// Use the passed timing first, but it could be nil or a strange length.
	if len(timings) >= 2 {
		return timings[0], timings[1]
	}

	var interval *time.Duration

	// Use the passed timings if only interval is provided.
	if len(timings) == 1 {
		interval = &timings[0]
	}

	di, timeout := environment.PollTimingsFromContext(ctx)
	if interval == nil {
		interval = &di
	}

	return *interval, timeout
}

// WaitForReadyOrDone will wait for a resource to become ready or succeed.
// Timing is optional but if provided is [interval, timeout].
func WaitForReadyOrDone(ctx context.Context, ref corev1.ObjectReference, timing ...time.Duration) error {
	interval, timeout := PollTimings(ctx, timing)

	k := ref.GroupVersionKind()
	gvr, _ := meta.UnsafeGuessKindToResource(k)

	switch gvr.Resource {
	case "jobs":
		err := WaitUntilJobDone(ctx, kubeclient.Get(ctx), ref.Namespace, ref.Name, interval, timeout)
		if err != nil {
			return err
		}
		return nil

	default:
		err := WaitForResourceReady(ctx, ref.Namespace, ref.Name, gvr, interval, timeout)
		if err != nil {
			return err
		}
	}

	return nil
}

// WaitForResourceReady waits until the specified resource in the given namespace are ready.
// Timing is optional but if provided is [interval, timeout].
func WaitForResourceReady(ctx context.Context, namespace, name string, gvr schema.GroupVersionResource, timing ...time.Duration) error {
	interval, timeout := PollTimings(ctx, timing)

	lastMsg := ""
	like := &duckv1.KResource{}
	return wait.PollImmediate(interval, timeout, func() (bool, error) {
		client := dynamicclient.Get(ctx)

		us, err := client.Resource(gvr).Namespace(namespace).Get(ctx, name, metav1.GetOptions{})
		if err != nil {
			if apierrors.IsNotFound(err) {
				log.Println(namespace, name, "not found", err)
				// keep polling
				return false, nil
			}
			return false, err
		}
		obj := like.DeepCopy()
		if err = runtime.DefaultUnstructuredConverter.FromUnstructured(us.Object, obj); err != nil {
			log.Fatalf("Error DefaultUnstructuree.Dynamiconverter. %v", err)
		}
		obj.ResourceVersion = gvr.Version
		obj.APIVersion = gvr.GroupVersion().String()

		// First see if the resource has conditions.
		if len(obj.Status.Conditions) == 0 {
			return false, nil // keep polling
		}

		// Ready type.
		ready := obj.Status.GetCondition(apis.ConditionReady)
		if ready != nil {
			// Succeeded type.
			ready = obj.Status.GetCondition(apis.ConditionSucceeded)
		}
		// Test Ready or Succeeded.
		if ready != nil {
			if !ready.IsTrue() {
				msg := fmt.Sprintf("%s is not %s, %s: %s", name, ready.Type, ready.Reason, ready.Message)
				if msg != lastMsg {
					log.Println(msg)
					lastMsg = msg
				}
			}

			log.Printf("%s is %s, %s: %s\n", name, ready.Type, ready.Reason, ready.Message)
			return ready.IsTrue(), nil
		}

		// Last resort, look at all conditions.
		// As a side-effect of this test,
		//   if a resource has no conditions, then it is ready.
		allReady := true
		for _, c := range obj.Status.Conditions {
			if !c.IsTrue() {
				msg := fmt.Sprintf("%s is not %s, %s: %s", name, c.Type, c.Reason, c.Message)
				if msg != lastMsg {
					log.Println(msg)
					lastMsg = msg
				}
				allReady = false
				break
			}
		}
		return allReady, nil
	})
}

// WaitForServiceEndpointsOrFail wraps the utility from pkg and uses the context to extract kubeclient and namespace
func WaitForServiceEndpointsOrFail(ctx context.Context, t feature.T, svcName string, numberOfExpectedEndpoints int) {
	if err := pkgtest.WaitForServiceEndpoints(ctx, kubeclient.Get(ctx), svcName, environment.FromContext(ctx).Namespace(), numberOfExpectedEndpoints); err != nil {
		t.Fatalf("Failed while waiting for %d endpoints in service %s: %+v", numberOfExpectedEndpoints, svcName, errors.WithStack(err))
	}
}

// WaitForPodRunningOrFail wraps the utility from pkg and uses the context to extract kubeclient and namespace
func WaitForPodRunningOrFail(ctx context.Context, t feature.T, podName string) {
	client := kubeclient.Get(ctx)
	namespace := environment.FromContext(ctx).Namespace()
	if err := pkgtest.WaitForPodRunning(ctx, client, podName, namespace); err != nil {
		sb := strings.Builder{}
		if p, err := client.CoreV1().Pods(namespace).Get(ctx, podName, metav1.GetOptions{}); err != nil {
			sb.WriteString(err.Error())
			sb.WriteString("\n")
		} else {
			for _, c := range p.Spec.Containers {
				if b, err := pkgtest.PodLogs(ctx, client, podName, c.Name, namespace); err != nil {
					sb.WriteString(err.Error())
				} else {
					sb.Write(b)
				}
				sb.WriteString("\n")
			}
		}
		t.Fatalf("Failed while waiting for pod %s running: %+v\n%s", podName, errors.WithStack(err), sb.String())
	}
}

// WaitForAddress waits until a resource has an address.
// Timing is optional but if provided is [interval, timeout].
func WaitForAddress(ctx context.Context, gvr schema.GroupVersionResource, name string, timing ...time.Duration) (*apis.URL, error) {
	interval, timeout := PollTimings(ctx, timing)

	var addr *apis.URL
	err := wait.PollImmediate(interval, timeout, func() (bool, error) {
		var err error
		addr, err = Address(ctx, gvr, name)
		if err == nil && addr == nil {
			// keep polling
			return false, nil
		}
		if err != nil {
			if apierrors.IsNotFound(err) {
				// keep polling
				return false, nil
			}
			// seems fatal.
			return false, err
		}
		// success!
		return true, nil
	})
	return addr, err
}
<|endoftext|>


<commit_before>// Copyright 2016 Koichi Shiraishi. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package commands

import (
	"bufio"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"
	"time"

	"nvim-go/context"
	"nvim-go/nvim"
	"nvim-go/nvim/profile"

	"github.com/cweill/gotests/gotests/process"
	"github.com/garyburd/neovim-go/vim"
	"github.com/garyburd/neovim-go/vim/plugin"
)

func init() {
	plugin.HandleCommand("GoGenerateTest", &plugin.CommandOptions{NArgs: "*", Complete: "file", Eval: "expand('%:p:h')"}, cmdGenerateTest)
}

func cmdGenerateTest(v *vim.Vim, files []string, dir string) {
	go GenerateTest(v, files, dir)
}

// GenerateTest generates the test files based by current buffer or args files
// functions.
// TODO(zchee): Currently Support '-all' flag only.
// Needs support -excl, -exported, -i, -only flags.
func GenerateTest(v *vim.Vim, files []string, dir string) error {
	defer profile.Start(time.Now(), "GenerateTest")
	var ctxt = context.Build{}
	defer ctxt.SetContext(filepath.Dir(dir))()

	b, err := v.CurrentBuffer()
	if err != nil {
		return nvim.Echoerr(v, "GoGenerateTest: %v", err)
	}

	if len(files) == 0 {
		f, err := v.BufferName(b)
		if err != nil {
			return nvim.Echoerr(v, "GoGenerateTest: %v", err)
		}
		files = append(files, f)
	}

	var opt = process.Options{
		AllFuncs:    true,
		ExclFuncs:   "init",
		WriteOutput: true,
		PrintInputs: true,
	}

	oldStdout := os.Stdout
	r, w, _ := os.Pipe()
	os.Stdout = w

	process.Run(w, files, &opt)

	w.Close()
	os.Stdout = oldStdout

	var genFuncs string
	scan := bufio.NewScanner(r)
	for scan.Scan() {
		genFuncs += scan.Text() + "\n"
	}

	// TODO(zchee): More beautiful code
	suffix := "_test.go "
	var ftests, ftestsRel string
	for _, f := range files {
		fnAbs := strings.Split(f, filepath.Ext(f))
		ftests += fnAbs[0] + suffix

		_, fnRel := filepath.Split(fnAbs[0])
		ftestsRel += fnRel + suffix
	}
	log.Println(ftests, ftestsRel)

	ask := fmt.Sprintf("%s\nGoGenerateTest: Generated %s\nGoGenerateTest: Open it? (y, n): ", genFuncs, ftestsRel)
	var answer interface{}
	if err := v.Call("input", &answer, ask); err != nil {
		return err
	}

	// TODO(zchee): Support open the ftests[0] file only.
	// If passes multiple files for 'edit' commands, occur 'E172: Only one file name allowed' errror.
	if answer.(string) != "n" {
		return v.Command(fmt.Sprintf("edit %s", ftests))
	}

	return nil
}
<commit_msg>cmds/generate: Remove unnecessary print log<commit_after>// Copyright 2016 Koichi Shiraishi. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package commands

import (
	"bufio"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"time"

	"nvim-go/context"
	"nvim-go/nvim"
	"nvim-go/nvim/profile"

	"github.com/cweill/gotests/gotests/process"
	"github.com/garyburd/neovim-go/vim"
	"github.com/garyburd/neovim-go/vim/plugin"
)

func init() {
	plugin.HandleCommand("GoGenerateTest", &plugin.CommandOptions{NArgs: "*", Complete: "file", Eval: "expand('%:p:h')"}, cmdGenerateTest)
}

func cmdGenerateTest(v *vim.Vim, files []string, dir string) {
	go GenerateTest(v, files, dir)
}

// GenerateTest generates the test files based by current buffer or args files
// functions.
// TODO(zchee): Currently Support '-all' flag only.
// Needs support -excl, -exported, -i, -only flags.
func GenerateTest(v *vim.Vim, files []string, dir string) error {
	defer profile.Start(time.Now(), "GenerateTest")
	var ctxt = context.Build{}
	defer ctxt.SetContext(filepath.Dir(dir))()

	b, err := v.CurrentBuffer()
	if err != nil {
		return nvim.Echoerr(v, "GoGenerateTest: %v", err)
	}

	if len(files) == 0 {
		f, err := v.BufferName(b)
		if err != nil {
			return nvim.Echoerr(v, "GoGenerateTest: %v", err)
		}
		files = append(files, f)
	}

	var opt = process.Options{
		AllFuncs:    true,
		ExclFuncs:   "init",
		WriteOutput: true,
		PrintInputs: true,
	}

	oldStdout := os.Stdout
	r, w, _ := os.Pipe()
	os.Stdout = w

	process.Run(w, files, &opt)

	w.Close()
	os.Stdout = oldStdout

	var genFuncs string
	scan := bufio.NewScanner(r)
	for scan.Scan() {
		genFuncs += scan.Text() + "\n"
	}

	// TODO(zchee): More beautiful code
	suffix := "_test.go "
	var ftests, ftestsRel string
	for _, f := range files {
		fnAbs := strings.Split(f, filepath.Ext(f))
		ftests += fnAbs[0] + suffix

		_, fnRel := filepath.Split(fnAbs[0])
		ftestsRel += fnRel + suffix
	}

	ask := fmt.Sprintf("%s\nGoGenerateTest: Generated %s\nGoGenerateTest: Open it? (y, n): ", genFuncs, ftestsRel)
	var answer interface{}
	if err := v.Call("input", &answer, ask); err != nil {
		return err
	}

	// TODO(zchee): Support open the ftests[0] file only.
	// If passes multiple files for 'edit' commands, occur 'E172: Only one file name allowed' errror.
	if answer.(string) != "n" {
		return v.Command(fmt.Sprintf("edit %s", ftests))
	}

	return nil
}
<|endoftext|>


<commit_before>package process

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"kego.io/json"
	"kego.io/system"
)

func Scan(dir string, packageName string, packagePath string, imports map[string]string, types map[string]*system.Type) error {

	walker := func(path string, file os.FileInfo, err error) error {
		if strings.HasSuffix(path, ".json") {

			file, err := ioutil.ReadFile(path)
			if err != nil {
				return fmt.Errorf("Error reading file %v in %v:\n%v\n", path, packageName, err)
			}

			context := &json.Context{
				PackageName: packageName,
				PackagePath: packagePath,
				Imports:     imports,
			}

			var i interface{}
			if err := json.UnmarshalTyped(file, &i, context); err != nil {
				return fmt.Errorf("Error when processing %v:\n%v\n", path, err)
			}

			t, ok := i.(*system.Type)
			if ok {
				fullname := fmt.Sprintf("%s:%s", packagePath, t.Id.Value)
				types[fullname] = t
				if t.Rule != nil {
					rulename := fmt.Sprintf("%s:%s", packagePath, t.Rule.Id.Value)
					types[rulename] = t.Rule
				}
			}

			return nil

		}
		return nil
	}

	if err := filepath.Walk(dir, walker); err != nil {
		return fmt.Errorf("Error while scanning for types:\n%v\n", err)
	}
	return nil
}
<commit_msg>Removed json.Context<commit_after>package process

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"kego.io/json"
	"kego.io/system"
)

func Scan(dir string, packageName string, packagePath string, imports map[string]string, types map[string]*system.Type) error {

	walker := func(path string, file os.FileInfo, err error) error {
		if strings.HasSuffix(path, ".json") {

			file, err := ioutil.ReadFile(path)
			if err != nil {
				return fmt.Errorf("Error reading file %v in %v:\n%v\n", path, packageName, err)
			}

			var i interface{}
			if err := json.UnmarshalTyped(file, &i, packagePath, imports); err != nil {
				return fmt.Errorf("Error when processing %v:\n%v\n", path, err)
			}

			t, ok := i.(*system.Type)
			if ok {
				fullname := fmt.Sprintf("%s:%s", packagePath, t.Id.Value)
				types[fullname] = t
				if t.Rule != nil {
					rulename := fmt.Sprintf("%s:%s", packagePath, t.Rule.Id.Value)
					types[rulename] = t.Rule
				}
			}

			return nil

		}
		return nil
	}

	if err := filepath.Walk(dir, walker); err != nil {
		return fmt.Errorf("Error while scanning for types:\n%v\n", err)
	}
	return nil
}
<|endoftext|>