<commit_before>package filepathfilter

import (
	"fmt"
	"path/filepath"
	"regexp"
	"strings"
)

type Pattern interface {
	Match(filename string) bool
}

type Filter struct {
	include []Pattern
	exclude []Pattern
}

func NewFromPatterns(include, exclude []Pattern) *Filter {
	return &Filter{include: include, exclude: exclude}
}

func New(include, exclude []string) *Filter {
	return NewFromPatterns(convertToPatterns(include), convertToPatterns(exclude))
}

func (f *Filter) Allows(filename string) bool {
	if f == nil {
		return true
	}

	if len(f.include)+len(f.exclude) == 0 {
		return true
	}

	cleanedName := filepath.Clean(filename)

	if len(f.include) > 0 {
		matched := false
		for _, inc := range f.include {
			matched = inc.Match(cleanedName)
			if matched {
				break
			}
		}
		if !matched {
			return false
		}
	}

	if len(f.exclude) > 0 {
		for _, ex := range f.exclude {
			if ex.Match(cleanedName) {
				return false
			}
		}
	}

	return true
}

func NewPattern(rawpattern string) Pattern {
	cleanpattern := filepath.Clean(rawpattern)

	// Special case local dir, matches all (inc subpaths)
	if _, local := localDirSet[cleanpattern]; local {
		return noOpMatcher{}
	}

	sep := string(filepath.Separator)
	hasPathSep := strings.Contains(cleanpattern, sep)
	ext := filepath.Ext(cleanpattern)
	plen := len(cleanpattern)
	if plen > 1 && !hasPathSep && strings.HasPrefix(cleanpattern, "*") && cleanpattern[1:plen] == ext {
		return &simpleExtPattern{ext: ext}
	}

	// special case * when there are no path separators
	// filepath.Match never allows * to match a path separator, which is correct
	// for gitignore IF the pattern includes a path separator, but not otherwise
	// So *.txt should match in any subdir, as should test*, but sub/*.txt would
	// only match directly in the sub dir
	// Don't need to test cross-platform separators as both cleaned above
	if !hasPathSep && strings.Contains(cleanpattern, "*") {
		pattern := regexp.QuoteMeta(cleanpattern)
		regpattern := fmt.Sprintf("^%s$", strings.Replace(pattern, "\\*", ".*", -1))
		return &pathlessWildcardPattern{
			rawPattern: cleanpattern,
			wildcardRE: regexp.MustCompile(regpattern),
		}
	}

	// Also support ** with path separators
	if hasPathSep && strings.Contains(cleanpattern, "**") {
		pattern := regexp.QuoteMeta(cleanpattern)
		regpattern := fmt.Sprintf("^%s$", strings.Replace(pattern, "\\*\\*", ".*", -1))
		return &doubleWildcardPattern{
			rawPattern: cleanpattern,
			wildcardRE: regexp.MustCompile(regpattern),
		}
	}

	if hasPathSep && strings.HasPrefix(cleanpattern, sep) {
		rel := cleanpattern[1:len(cleanpattern)]
		prefix := rel
		if strings.HasSuffix(rel, sep) {
			rel = rel[0 : len(rel)-1]
		} else {
			prefix += sep
		}

		return &pathPrefixPattern{
			rawPattern: cleanpattern,
			relative:   rel,
			prefix:     prefix,
		}
	}

	return &pathPattern{
		rawPattern: cleanpattern,
		prefix:     cleanpattern + sep,
		suffix:     sep + cleanpattern,
		inner:      sep + cleanpattern + sep,
	}
}

func convertToPatterns(rawpatterns []string) []Pattern {
	patterns := make([]Pattern, len(rawpatterns))
	for i, raw := range rawpatterns {
		patterns[i] = NewPattern(raw)
	}
	return patterns
}

type pathPrefixPattern struct {
	rawPattern string
	relative   string
	prefix     string
}

// Match is a revised version of filepath.Match which makes it behave more
// like gitignore
func (p *pathPrefixPattern) Match(name string) bool {
	if name == p.relative || strings.HasPrefix(name, p.prefix) {
		return true
	}
	matched, _ := filepath.Match(p.rawPattern, name)
	return matched
}

// String returns a string representation of the underlying pattern for which
// this *pathPrefixPattern is matching.
func (p *pathPrefixPattern) String() string {
	return p.rawPattern
}

type pathPattern struct {
	rawPattern string
	prefix     string
	suffix     string
	inner      string
}

// Match is a revised version of filepath.Match which makes it behave more
// like gitignore
func (p *pathPattern) Match(name string) bool {
	if strings.HasPrefix(name, p.prefix) || strings.HasSuffix(name, p.suffix) || strings.Contains(name, p.inner) {
		return true
	}
	matched, _ := filepath.Match(p.rawPattern, name)
	return matched
}

// String returns a string representation of the underlying pattern for which
// this *pathPattern is matching.
func (p *pathPattern) String() string {
	return p.rawPattern
}

type simpleExtPattern struct {
	ext string
}

func (p *simpleExtPattern) Match(name string) bool {
	return strings.HasSuffix(name, p.ext)
}

// String returns a string representation of the underlying pattern for which
// this *simpleExtPattern is matching.
func (p *simpleExtPattern) String() string {
	return fmt.Sprintf("*%s", p.ext)
}

type pathlessWildcardPattern struct {
	rawPattern string
	wildcardRE *regexp.Regexp
}

// Match is a revised version of filepath.Match which makes it behave more
// like gitignore
func (p *pathlessWildcardPattern) Match(name string) bool {
	matched, _ := filepath.Match(p.rawPattern, name)
	// Match the whole of the base name but allow matching in folders if no path
	return matched || p.wildcardRE.MatchString(filepath.Base(name))
}

// String returns a string representation of the underlying pattern for which
// this *pathlessWildcardPattern is matching.
func (p *pathlessWildcardPattern) String() string {
	return p.rawPattern
}

type doubleWildcardPattern struct {
	rawPattern string
	wildcardRE *regexp.Regexp
}

// Match is a revised version of filepath.Match which makes it behave more
// like gitignore
func (p *doubleWildcardPattern) Match(name string) bool {
	matched, _ := filepath.Match(p.rawPattern, name)
	// Match the whole of the base name but allow matching in folders if no path
	return matched || p.wildcardRE.MatchString(name)
}

// String returns a string representation of the underlying pattern for which
// this *doubleWildcardPattern is matching.
func (p *doubleWildcardPattern) String() string {
	return p.rawPattern
}

type noOpMatcher struct {
}

func (n noOpMatcher) Match(name string) bool {
	return true
}

var localDirSet = map[string]struct{}{
	".":   struct{}{},
	"./":  struct{}{},
	".\\": struct{}{},
}
<commit_msg>filepathfilter: implement String() on noOpMatcher<commit_after>package filepathfilter

import (
	"fmt"
	"path/filepath"
	"regexp"
	"strings"
)

type Pattern interface {
	Match(filename string) bool
}

type Filter struct {
	include []Pattern
	exclude []Pattern
}

func NewFromPatterns(include, exclude []Pattern) *Filter {
	return &Filter{include: include, exclude: exclude}
}

func New(include, exclude []string) *Filter {
	return NewFromPatterns(convertToPatterns(include), convertToPatterns(exclude))
}

func (f *Filter) Allows(filename string) bool {
	if f == nil {
		return true
	}

	if len(f.include)+len(f.exclude) == 0 {
		return true
	}

	cleanedName := filepath.Clean(filename)

	if len(f.include) > 0 {
		matched := false
		for _, inc := range f.include {
			matched = inc.Match(cleanedName)
			if matched {
				break
			}
		}
		if !matched {
			return false
		}
	}

	if len(f.exclude) > 0 {
		for _, ex := range f.exclude {
			if ex.Match(cleanedName) {
				return false
			}
		}
	}

	return true
}

func NewPattern(rawpattern string) Pattern {
	cleanpattern := filepath.Clean(rawpattern)

	// Special case local dir, matches all (inc subpaths)
	if _, local := localDirSet[cleanpattern]; local {
		return noOpMatcher{}
	}

	sep := string(filepath.Separator)
	hasPathSep := strings.Contains(cleanpattern, sep)
	ext := filepath.Ext(cleanpattern)
	plen := len(cleanpattern)
	if plen > 1 && !hasPathSep && strings.HasPrefix(cleanpattern, "*") && cleanpattern[1:plen] == ext {
		return &simpleExtPattern{ext: ext}
	}

	// special case * when there are no path separators
	// filepath.Match never allows * to match a path separator, which is correct
	// for gitignore IF the pattern includes a path separator, but not otherwise
	// So *.txt should match in any subdir, as should test*, but sub/*.txt would
	// only match directly in the sub dir
	// Don't need to test cross-platform separators as both cleaned above
	if !hasPathSep && strings.Contains(cleanpattern, "*") {
		pattern := regexp.QuoteMeta(cleanpattern)
		regpattern := fmt.Sprintf("^%s$", strings.Replace(pattern, "\\*", ".*", -1))
		return &pathlessWildcardPattern{
			rawPattern: cleanpattern,
			wildcardRE: regexp.MustCompile(regpattern),
		}
	}

	// Also support ** with path separators
	if hasPathSep && strings.Contains(cleanpattern, "**") {
		pattern := regexp.QuoteMeta(cleanpattern)
		regpattern := fmt.Sprintf("^%s$", strings.Replace(pattern, "\\*\\*", ".*", -1))
		return &doubleWildcardPattern{
			rawPattern: cleanpattern,
			wildcardRE: regexp.MustCompile(regpattern),
		}
	}

	if hasPathSep && strings.HasPrefix(cleanpattern, sep) {
		rel := cleanpattern[1:len(cleanpattern)]
		prefix := rel
		if strings.HasSuffix(rel, sep) {
			rel = rel[0 : len(rel)-1]
		} else {
			prefix += sep
		}

		return &pathPrefixPattern{
			rawPattern: cleanpattern,
			relative:   rel,
			prefix:     prefix,
		}
	}

	return &pathPattern{
		rawPattern: cleanpattern,
		prefix:     cleanpattern + sep,
		suffix:     sep + cleanpattern,
		inner:      sep + cleanpattern + sep,
	}
}

func convertToPatterns(rawpatterns []string) []Pattern {
	patterns := make([]Pattern, len(rawpatterns))
	for i, raw := range rawpatterns {
		patterns[i] = NewPattern(raw)
	}
	return patterns
}

type pathPrefixPattern struct {
	rawPattern string
	relative   string
	prefix     string
}

// Match is a revised version of filepath.Match which makes it behave more
// like gitignore
func (p *pathPrefixPattern) Match(name string) bool {
	if name == p.relative || strings.HasPrefix(name, p.prefix) {
		return true
	}
	matched, _ := filepath.Match(p.rawPattern, name)
	return matched
}

// String returns a string representation of the underlying pattern for which
// this *pathPrefixPattern is matching.
func (p *pathPrefixPattern) String() string {
	return p.rawPattern
}

type pathPattern struct {
	rawPattern string
	prefix     string
	suffix     string
	inner      string
}

// Match is a revised version of filepath.Match which makes it behave more
// like gitignore
func (p *pathPattern) Match(name string) bool {
	if strings.HasPrefix(name, p.prefix) || strings.HasSuffix(name, p.suffix) || strings.Contains(name, p.inner) {
		return true
	}
	matched, _ := filepath.Match(p.rawPattern, name)
	return matched
}

// String returns a string representation of the underlying pattern for which
// this *pathPattern is matching.
func (p *pathPattern) String() string {
	return p.rawPattern
}

type simpleExtPattern struct {
	ext string
}

func (p *simpleExtPattern) Match(name string) bool {
	return strings.HasSuffix(name, p.ext)
}

// String returns a string representation of the underlying pattern for which
// this *simpleExtPattern is matching.
func (p *simpleExtPattern) String() string {
	return fmt.Sprintf("*%s", p.ext)
}

type pathlessWildcardPattern struct {
	rawPattern string
	wildcardRE *regexp.Regexp
}

// Match is a revised version of filepath.Match which makes it behave more
// like gitignore
func (p *pathlessWildcardPattern) Match(name string) bool {
	matched, _ := filepath.Match(p.rawPattern, name)
	// Match the whole of the base name but allow matching in folders if no path
	return matched || p.wildcardRE.MatchString(filepath.Base(name))
}

// String returns a string representation of the underlying pattern for which
// this *pathlessWildcardPattern is matching.
func (p *pathlessWildcardPattern) String() string {
	return p.rawPattern
}

type doubleWildcardPattern struct {
	rawPattern string
	wildcardRE *regexp.Regexp
}

// Match is a revised version of filepath.Match which makes it behave more
// like gitignore
func (p *doubleWildcardPattern) Match(name string) bool {
	matched, _ := filepath.Match(p.rawPattern, name)
	// Match the whole of the base name but allow matching in folders if no path
	return matched || p.wildcardRE.MatchString(name)
}

// String returns a string representation of the underlying pattern for which
// this *doubleWildcardPattern is matching.
func (p *doubleWildcardPattern) String() string {
	return p.rawPattern
}

type noOpMatcher struct {
}

func (n noOpMatcher) Match(name string) bool {
	return true
}

func (n noOpMatcher) String() string {
	return ""
}

var localDirSet = map[string]struct{}{
	".":   struct{}{},
	"./":  struct{}{},
	".\\": struct{}{},
}
<|endoftext|>


<commit_before>package sqlr

import (
	"database/sql"
	"fmt"
	"log"
	"os"

	_ "github.com/mattn/go-sqlite3"
)

// The UserRow struct represents a single row in the users table.
// Note that this package becomes more useful when tables
// have many more columns than shown in this example.
type UserRow struct {
	ID         int64 `sql:"primary key autoincrement"`
	GivenName  string
	FamilyName string
}

func Example() {
	db, err := sql.Open("sqlite3", ":memory:")
	exitIfError(err)
	setupSchema(db)

	tx, err := db.Begin()
	exitIfError(err)
	defer tx.Rollback()

	schema := NewSchema(ForDB(db))

	// insert three rows, IDs are automatically generated (1, 2, 3)
	for _, givenName := range []string{"John", "Jane", "Joan"} {
		u := &UserRow{
			GivenName:  givenName,
			FamilyName: "Citizen",
		}
		_, err = schema.Exec(tx, u, `insert into users`)
		exitIfError(err)
	}

	// get user with ID of 3 and then delete it
	{
		var u UserRow
		_, err = schema.Select(tx, &u, `select users`, 3)
		exitIfError(err)

		_, err = schema.Exec(tx, u, `delete from users where {}`)
		exitIfError(err)
	}

	// update family name for user with ID of 2
	{
		var u UserRow
		_, err = schema.Select(tx, &u, `select users`, 2)
		exitIfError(err)

		u.FamilyName = "Doe"
		_, err = schema.Exec(tx, u, `update users`)
		exitIfError(err)
	}

	// select rows from table and print
	{
		var users []*UserRow
		_, err = schema.Select(tx, &users, `
			select {}
			from users
			order by id
			limit ? offset ?`, 100, 0)
		exitIfError(err)
		for _, u := range users {
			fmt.Printf("User %d: %s, %s\n", u.ID, u.FamilyName, u.GivenName)
		}
	}

	// Output:
	// User 1: Citizen, John
	// User 2: Doe, Jane
}

func exitIfError(err error) {
	if err != nil {
		log.Output(2, err.Error())
		os.Exit(1)
	}
}

func init() {
	log.SetFlags(log.Lshortfile)
}

func setupSchema(db *sql.DB) {
	_, err := db.Exec(`
		create table users(
			id integer primary key autoincrement,
			given_name text,
			family_name text
		)
	`)
	exitIfError(err)
}
<commit_msg>Remove example_test.go; package example.<commit_after><|endoftext|>


<commit_before>package nats_test

import (
	"fmt"
	"github.com/apcera/nats"
	"time"
)

// Show different ways to create a Conn
func ExampleConnect() {

	nats.Connect(nats.DefaultURL)
	nats.Connect("nats://derek:secretpassword@nats.apcera.com:421")

	opts := nats.Options{
		AllowReconnect : true,
		MaxReconnect   : 10,
		ReconnectWait  : 5 * time.Second,
		Timeout        : 1 * time.Second,
	}

	nc, _ := opts.Connect()
	nc.Close()
}

// This Example shows an asynchronous subscriber.
func ExampleConn_Subscribe() {
	nc, _ := nats.Connect(nats.DefaultURL)
	defer nc.Close()

	nc.Subscribe("foo", func(m *nats.Msg) {
		fmt.Printf("Received a message: %s\n", string(m.Data))
	})
}

// This Example shows a synchronous subscriber.
func ExampleConn_SubscribeSync() {
	nc, _ := nats.Connect(nats.DefaultURL)
	defer nc.Close()

	sub, _ := nc.SubscribeSync("foo")
	m, err := sub.NextMsg(1 * time.Second)
	if err == nil {
		fmt.Printf("Received a message: %s\n", string(m.Data))
	} else {
		fmt.Println("NextMsg timed out.")
	}
}

func ExampleSubscription_NextMsg() {
	nc, _ := nats.Connect(nats.DefaultURL)
	defer nc.Close()

	sub, _ := nc.SubscribeSync("foo")
	m, err := sub.NextMsg(1*time.Second)
	if err == nil {
		fmt.Printf("Received a message: %s\n", string(m.Data))
	} else {
		fmt.Println("NextMsg timed out.")
	}
}

func ExampleSubscription_Unsubscribe() {
	nc, _ := nats.Connect(nats.DefaultURL)
	defer nc.Close()

	sub, _ := nc.SubscribeSync("foo")
	// ...
	sub.Unsubscribe()
}

func ExampleConn_Publish() {
	nc, _ := nats.Connect(nats.DefaultURL)
	defer nc.Close()

	nc.Publish("foo", []byte("Hello World!"))
}

func ExampleConn_PublishMsg() {
	nc, _ := nats.Connect(nats.DefaultURL)
	defer nc.Close()

	msg := &nats.Msg{Subject: "foo", Reply: "bar", Data: []byte("Hello World!")}
	nc.PublishMsg(msg)
}

func ExampleConn_Flush() {
	nc, _ := nats.Connect(nats.DefaultURL)
	defer nc.Close()

	msg := &nats.Msg{Subject:"foo", Reply:"bar", Data:[]byte("Hello World!")}
	for i := 0 ; i < 1000 ; i++ {
		nc.PublishMsg(msg)
	}
	err := nc.Flush()
	if err == nil {
		// Everything has been processed by the server for nc *Conn.
	}
}

func ExampleConn_FlushTimeout() {
	nc, _ := nats.Connect(nats.DefaultURL)
	defer nc.Close()

	msg := &nats.Msg{Subject: "foo", Reply: "bar", Data: []byte("Hello World!")}
	for i := 0; i < 1000; i++ {
		nc.PublishMsg(msg)
	}
	// Only wait up to 1 second for Flush
	err := nc.FlushTimeout(1 * time.Second)
	if err == nil {
		// Everything has been processed by the server for nc *Conn.
	}
}

func ExampleConn_Request() {
	nc, _ := nats.Connect(nats.DefaultURL)
	defer nc.Close()

	nc.Subscribe("foo", func(m *nats.Msg) {
		nc.Publish(m.Reply, []byte("I will help you"))
	})
	nc.Request("foo", []byte("help"), 50*time.Millisecond)
}

func ExampleConn_QueueSubscribe() {
	nc, _ := nats.Connect(nats.DefaultURL)
	defer nc.Close()

	received := 0

	nc.QueueSubscribe("foo", "worker_group", func(_ *nats.Msg) {
		received += 1
	})
}

func ExampleSubscription_AutoUnsubscribe() {
	nc, _ := nats.Connect(nats.DefaultURL)
	defer nc.Close()

	received, wanted, total := 0, 10, 100

	sub, _ := nc.Subscribe("foo",  func(_ *nats.Msg) {
		received += 1
	})
	sub.AutoUnsubscribe(wanted)

	for i := 0; i < total; i++ {
		nc.Publish("foo", []byte("Hello"))
	}
	nc.Flush()

	fmt.Printf("Received = %d", received)
}

func ExampleConn_Close() {
	nc, _ := nats.Connect(nats.DefaultURL)
	nc.Close()
}<commit_msg>Added EncodedConn examples<commit_after>package nats_test

import (
	"fmt"
	"github.com/apcera/nats"
	"time"
)

// Show different ways to create a Conn
func ExampleConnect() {

	nats.Connect(nats.DefaultURL)
	nats.Connect("nats://derek:secretpassword@nats.apcera.com:421")

	opts := nats.Options{
		AllowReconnect : true,
		MaxReconnect   : 10,
		ReconnectWait  : 5 * time.Second,
		Timeout        : 1 * time.Second,
	}

	nc, _ := opts.Connect()
	nc.Close()
}

// This Example shows an asynchronous subscriber.
func ExampleConn_Subscribe() {
	nc, _ := nats.Connect(nats.DefaultURL)
	defer nc.Close()

	nc.Subscribe("foo", func(m *nats.Msg) {
		fmt.Printf("Received a message: %s\n", string(m.Data))
	})
}

// This Example shows a synchronous subscriber.
func ExampleConn_SubscribeSync() {
	nc, _ := nats.Connect(nats.DefaultURL)
	defer nc.Close()

	sub, _ := nc.SubscribeSync("foo")
	m, err := sub.NextMsg(1 * time.Second)
	if err == nil {
		fmt.Printf("Received a message: %s\n", string(m.Data))
	} else {
		fmt.Println("NextMsg timed out.")
	}
}

func ExampleSubscription_NextMsg() {
	nc, _ := nats.Connect(nats.DefaultURL)
	defer nc.Close()

	sub, _ := nc.SubscribeSync("foo")
	m, err := sub.NextMsg(1*time.Second)
	if err == nil {
		fmt.Printf("Received a message: %s\n", string(m.Data))
	} else {
		fmt.Println("NextMsg timed out.")
	}
}

func ExampleSubscription_Unsubscribe() {
	nc, _ := nats.Connect(nats.DefaultURL)
	defer nc.Close()

	sub, _ := nc.SubscribeSync("foo")
	// ...
	sub.Unsubscribe()
}

func ExampleConn_Publish() {
	nc, _ := nats.Connect(nats.DefaultURL)
	defer nc.Close()

	nc.Publish("foo", []byte("Hello World!"))
}

func ExampleConn_PublishMsg() {
	nc, _ := nats.Connect(nats.DefaultURL)
	defer nc.Close()

	msg := &nats.Msg{Subject: "foo", Reply: "bar", Data: []byte("Hello World!")}
	nc.PublishMsg(msg)
}

func ExampleConn_Flush() {
	nc, _ := nats.Connect(nats.DefaultURL)
	defer nc.Close()

	msg := &nats.Msg{Subject:"foo", Reply:"bar", Data:[]byte("Hello World!")}
	for i := 0 ; i < 1000 ; i++ {
		nc.PublishMsg(msg)
	}
	err := nc.Flush()
	if err == nil {
		// Everything has been processed by the server for nc *Conn.
	}
}

func ExampleConn_FlushTimeout() {
	nc, _ := nats.Connect(nats.DefaultURL)
	defer nc.Close()

	msg := &nats.Msg{Subject: "foo", Reply: "bar", Data: []byte("Hello World!")}
	for i := 0; i < 1000; i++ {
		nc.PublishMsg(msg)
	}
	// Only wait up to 1 second for Flush
	err := nc.FlushTimeout(1 * time.Second)
	if err == nil {
		// Everything has been processed by the server for nc *Conn.
	}
}

func ExampleConn_Request() {
	nc, _ := nats.Connect(nats.DefaultURL)
	defer nc.Close()

	nc.Subscribe("foo", func(m *nats.Msg) {
		nc.Publish(m.Reply, []byte("I will help you"))
	})
	nc.Request("foo", []byte("help"), 50*time.Millisecond)
}

func ExampleConn_QueueSubscribe() {
	nc, _ := nats.Connect(nats.DefaultURL)
	defer nc.Close()

	received := 0

	nc.QueueSubscribe("foo", "worker_group", func(_ *nats.Msg) {
		received += 1
	})
}

func ExampleSubscription_AutoUnsubscribe() {
	nc, _ := nats.Connect(nats.DefaultURL)
	defer nc.Close()

	received, wanted, total := 0, 10, 100

	sub, _ := nc.Subscribe("foo",  func(_ *nats.Msg) {
		received += 1
	})
	sub.AutoUnsubscribe(wanted)

	for i := 0; i < total; i++ {
		nc.Publish("foo", []byte("Hello"))
	}
	nc.Flush()

	fmt.Printf("Received = %d", received)
}

func ExampleConn_Close() {
	nc, _ := nats.Connect(nats.DefaultURL)
	nc.Close()
}

// Show how to wrap a Conn into an EncodedConn
func ExampleNewEncodedConn() {
	nc, _ := nats.Connect(nats.DefaultURL)
	c, _ := nats.NewEncodedConn(nc, "json")
	c.Close()
}

// EncodedConn can publish virtually anything just
// by passing it in. The encoder will be used to properly
// encode the raw Go type
func ExampleEncodedConn_Publish() {
	nc, _ := nats.Connect(nats.DefaultURL)
	c, _ := nats.NewEncodedConn(nc, "json")
	defer c.Close()

	type person struct {
		Name     string
		Address  string
		Age      int
	}

	me := &person{Name: "derek", Age: 22, Address: "85 Second St"}
	c.Publish("hello", me)
}

// EncodedConn's subscribers will automatically decode the
// wire data into the requested Go type using the Decode()
// method of the registered Encoder. The callback signature
// can also vary to include additional data, like subject and
// reply subjects.
func ExampleEncodedConn_Subscribe() {
	nc, _ := nats.Connect(nats.DefaultURL)
	c, _ := nats.NewEncodedConn(nc, "json")
	defer c.Close()

	type person struct {
		Name     string
		Address  string
		Age      int
	}

	c.Subscribe("hello", func(p *person) {
		fmt.Printf("Received a person! %+v\n", p)
	})

	c.Subscribe("hello", func(subj, reply string, p *person) {
		fmt.Printf("Received a person on subject %s! %+v\n", subj, p)
	})

	me := &person{Name: "derek", Age: 22, Address: "85 Second St"}
	c.Publish("hello", me)
}
<|endoftext|>


<commit_before>package aranGO

import "testing"
import "log"

type DocTest struct {
  Document // arango Document to save id, key, rev
  Name     string
  Age      int
  Likes    []string
}

func TestExample(t *testing.T) {
  // connect
  log.Println("start test")
  s,err := Connect("http://localhost:8529","diego","test",false)
  if err != nil{
    panic(err)
  }
  db := s.DB("_system")

  // test relations
  var i interface{}
  i = db.Col("vertex").Count()
  log.Println(i)

}
<commit_msg>example<commit_after>package aranGO

import "testing"
import "log"

type DocTest struct {
  Document // arango Document to save id, key, rev
  Name     string
  Age      int
  Likes    []string
}

func TestExample(t *testing.T) {
  // connect
  log.Println("start test")
  s,err := Connect("http://pampa.dev:8529","diego","test",true)
  if err != nil{
    panic(err)
  }
  db := s.DB("_system")

  if db == nil {
    panic("invalid db")
  }
  // test relations
  //ed := NewEdgeDefinition("edges",[]string{ "test" }, []string{ "test" })
  ed2 := NewEdgeDefinition("runs",[]string{ "test" }, []string{ "campaigns" })
  db.Graph("test1").AddEdge(ed2)

}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"net/url"
	"os"
	"os/signal"
	"path/filepath"
	"time"

	"github.com/gorilla/websocket"
	"github.com/mohae/autofact/conf"
	czap "github.com/mohae/zap"
	"github.com/uber-go/zap"
)

const (
	addressVar = "address"
	aVar       = "a"
	portVar    = "port"
	pVar       = "p"
)

var (
	connFile    = "autofact.json"
	collectFile = "autocollect.json"
	// This is the default directory for autofact-client app data.
	autofactPath    = "$HOME/.autofact"
	autofactEnvName = "AUTOFACT_PATH"
	// configuration info
	connConf conf.Conn

	// client configuration: used for serverless

	serverless bool
)

// Vars for logging and local data output, if applicable.
var (
	log      zap.Logger // application log
	loglevel = zap.LevelFlag("loglevel", zap.WarnLevel, "log level")
	logOut   string
	logFile  *os.File

	data     czap.Logger // use mohae's fork to support level description override
	dataOut  string
	dataFile *os.File
)

// TODO: reconcile these flags with config file usage.  Probably add contour
// to handle this after the next refactor of contour.
// TODO: make connectInterval/period handling consistent, e.g. should they be
// flags, what is precedence in relation to Conn?
func init() {
	flag.StringVar(&connConf.ServerAddress, addressVar, "127.0.0.1", "the server address")
	flag.StringVar(&connConf.ServerAddress, aVar, "127.0.0.1", "the server address (short)")
	flag.StringVar(&connConf.ServerPort, portVar, "8675", "the connection port")
	flag.StringVar(&connConf.ServerPort, pVar, "8675", "the connection port (short)")
	flag.StringVar(&logOut, "logout", "stderr", "log output; if empty stderr will be used")
	flag.StringVar(&logOut, "l", "stderr", "log output; if empty stderr will be used")
	flag.StringVar(&dataOut, "dataout", "stdout", "serverless mode data output, if empty stderr will be used")
	flag.StringVar(&dataOut, "d", "stdout", "serverless mode data output, if empty stderr will be used")
	flag.BoolVar(&serverless, "serverless", false, "serverless: the client will run standalone and write the collected data to the log")
	connConf.ConnectInterval.Duration = 5 * time.Second
	connConf.ConnectPeriod.Duration = 15 * time.Minute

	// override czap description for InfoLevel
	czap.WarnString = "data"
}

func main() {
	// Load the AUTOPATH value
	tmp := os.Getenv(autofactEnvName)
	if tmp != "" {
		autofactPath = tmp
	}
	autofactPath = os.ExpandEnv(autofactPath)

	// make sure the autofact path exists (create if it doesn't)
	err := os.MkdirAll(autofactPath, 0760)
	if err != nil {
		fmt.Fprintf(os.Stderr, "unable to create AUTOFACT_PATH: %s\n", err)
		fmt.Fprintln(os.Stderr, "startup error: exiting")
		os.Exit(1)
	}

	// finalize the paths
	connFile = filepath.Join(autofactPath, connFile)

	// process the settings: this gets read first just in case flags override
	var connMsg string
	err = connConf.Load(connFile)
	if err != nil {
		// capture the error for logging once it is setup and continue.  An error
		// is not a show stopper as the file may not exist if this is the first
		// time autofact has run on this node.
		connMsg = fmt.Sprintf("using default connection settings")
	}

	// Parse the flags.
	flag.Parse()

	// now that everything is parsed; set up logging
	SetLogging()
	defer CloseOut()
	// if there was an error reading the connection configuration and this isn't
	// being run serverless, log it
	if connMsg != "" && !serverless {
		log.Warn(
			err.Error(),
			zap.String("op", fmt.Sprintf("load %s", connFile)),
			zap.String("conf", connMsg),
		)
	}

	// TODO add env var support

	// get a client
	c := NewClient(connConf, collectFile)
	c.AutoPath = autofactPath

	// if serverless: load the collection configuration
	if serverless {
		collectFile = filepath.Join(autofactPath, collectFile)
		err = c.Collect.Load(collectFile)
		if err != nil {
			log.Warn(
				err.Error(),
				zap.String("op", fmt.Sprintf("load %s", collectFile)),
				zap.String("conf", "using default collect settings"),
			)
			c.Collect.UseDefaults()
			err = c.Collect.SaveJSON()
			if err != nil {
				log.Warn(
					err.Error(),
					zap.String("op", fmt.Sprintf("save %s", collectFile)),
				)
			}
		}
	}

	// handle signals
	go handleSignals(c)

	// doneCh is used to signal that the connection has been closed
	doneCh := make(chan struct{})

	// Set up the output destination.
	if serverless { // open the datafile to use
		SetDataOut()
		WriteSystemInfo()
	}

	if !serverless { // connect to the server
		// connect to the Server
		c.ServerURL = url.URL{Scheme: "ws", Host: fmt.Sprintf("%s:%s", c.ServerAddress, c.ServerPort), Path: "/client"}

		// must have a connection before doing anything
		for i := 0; i < 3; i++ {
			connected := c.Connect()
			if connected {
				break
			}
			// retry on fail until retry attempts have been exceeded
		}
		if !c.IsConnected() {
			log.Error(
				"unable to connect",
				zap.String("server", c.ServerURL.String()),
			)
			CloseOut() // defer doesn't run on fatal
			os.Exit(1)
		}
		// if connected, save the conf: this will also save the ClientID
		err = c.Conn.Save()
		if err != nil {
			log.Error(
				err.Error(),
				zap.String("op", "save conn"),
				zap.String("file", c.Conn.Filename),
			)
		}
	}

	// set up the data processing
	if serverless {
		// since there isn't a server pull for healthbeat, a local ticker is started
		go c.HealthbeatLocal(doneCh)
		c.CPUUtilization = c.CPUUtilizationLocal
		c.MemInfo = c.MemInfoLocal
		c.NetUsage = c.NetUsageLocal
	} else {
		// assign the
		c.LoadAvg = LoadAvgFB
		c.CPUUtilization = c.CPUUtilizationFB
		c.MemInfo = c.MemInfoFB
		c.NetUsage = c.NetUsageFB

		// start the listener
		go c.Listen(doneCh)
		// start the message writer
		go c.MessageWriter(doneCh)
	}

	go c.CPUUtilization(doneCh)
	go c.MemInfo(doneCh)
	go c.NetUsage(doneCh)

	<-doneCh
}

func SetLogging() {
	// if logfile is empty, use Stderr
	var err error
	if logOut == "" || logOut == "stderr" {
		logFile = os.Stderr
		goto newLog
	}
	if logOut == "stdout" {
		logFile = os.Stdout
		goto newLog
	}
	logFile, err = os.OpenFile(logOut, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0664)
	if err != nil {
		panic(err)
	}
newLog:
	log = zap.New(
		zap.NewJSONEncoder(
			zap.RFC3339Formatter("ts"),
		),
		zap.Output(logFile),
	)
	log.SetLevel(*loglevel)
}

func SetDataOut() {
	var err error
	if dataOut == "" || dataOut == "stdout" {
		dataFile = os.Stdout
		goto newData
	}
	if dataOut == "stderr" {
		dataFile = os.Stderr
		goto newData
	}
	dataFile, err = os.OpenFile(dataOut, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0664)
	if err != nil {
		log.Fatal(
			err.Error(),
			zap.String("op", "open datafile"),
			zap.String("filename", dataOut),
		)
	}
newData:
	data = czap.New(
		czap.NewJSONEncoder(
			czap.RFC3339Formatter("ts"),
		),
		czap.Output(dataFile),
	)
	data.SetLevel(czap.WarnLevel)
}

// CloseOut closes the local output destinations before shutdown.
func CloseOut() {
	if logFile != nil {
		logFile.Close()
	}
	// If running serverless, close the data file.
	if serverless {
		dataFile.Close()
	}
}

func handleSignals(c *Client) {
	ch := make(chan os.Signal, 1)
	signal.Notify(ch, os.Interrupt)
	v := <-ch
	log.Info(
		"os signal received: shutting down autofact",
		zap.Object("signal", v.String()),
	)
	// If there's a connection send a close signal
	if c.IsConnected() {
		log.Debug(
			"closing connection",
			zap.String("op", "shutdown"),
		)
		c.WS.WriteMessage(websocket.CloseMessage, []byte(string(c.Conn.ID)+" shutting down"))
	}
	CloseOut()

	os.Exit(1)
}
<commit_msg>add flag for collecting system information on startup when in serverless mode and handle<commit_after>package main

import (
	"flag"
	"fmt"
	"net/url"
	"os"
	"os/signal"
	"path/filepath"
	"time"

	"github.com/gorilla/websocket"
	"github.com/mohae/autofact/conf"
	czap "github.com/mohae/zap"
	"github.com/uber-go/zap"
)

const (
	addressVar = "address"
	aVar       = "a"
	portVar    = "port"
	pVar       = "p"
)

var (
	connFile    = "autofact.json"
	collectFile = "autocollect.json"
	// This is the default directory for autofact-client app data.
	autofactPath    = "$HOME/.autofact"
	autofactEnvName = "AUTOFACT_PATH"
	// configuration info
	connConf conf.Conn

	// client configuration: used for serverless
	serverless bool
	startInfo  bool
)

// Vars for logging and local data output, if applicable.
var (
	log      zap.Logger // application log
	loglevel = zap.LevelFlag("loglevel", zap.WarnLevel, "log level")
	logOut   string
	logFile  *os.File

	data     czap.Logger // use mohae's fork to support level description override
	dataOut  string
	dataFile *os.File
)

// TODO: reconcile these flags with config file usage.  Probably add contour
// to handle this after the next refactor of contour.
// TODO: make connectInterval/period handling consistent, e.g. should they be
// flags, what is precedence in relation to Conn?
func init() {
	flag.StringVar(&connConf.ServerAddress, addressVar, "127.0.0.1", "the server address")
	flag.StringVar(&connConf.ServerAddress, aVar, "127.0.0.1", "the server address (short)")
	flag.StringVar(&connConf.ServerPort, portVar, "8675", "the connection port")
	flag.StringVar(&connConf.ServerPort, pVar, "8675", "the connection port (short)")
	flag.StringVar(&logOut, "logout", "stderr", "log output; if empty stderr will be used")
	flag.StringVar(&logOut, "l", "stderr", "log output; if empty stderr will be used")
	flag.StringVar(&dataOut, "dataout", "stdout", "serverless mode data output, if empty stderr will be used")
	flag.StringVar(&dataOut, "d", "stdout", "serverless mode data output, if empty stderr will be used")
	flag.BoolVar(&serverless, "serverless", false, "serverless: the client will run standalone and write the collected data to the log")
	flag.BoolVar(&startInfo, "startinfo", false, "when operating serverless the client's system info will be collected on app start")
	connConf.ConnectInterval.Duration = 5 * time.Second
	connConf.ConnectPeriod.Duration = 15 * time.Minute

	// override czap description for InfoLevel
	czap.WarnString = "data"
}

func main() {
	// Load the AUTOPATH value
	tmp := os.Getenv(autofactEnvName)
	if tmp != "" {
		autofactPath = tmp
	}
	autofactPath = os.ExpandEnv(autofactPath)

	// make sure the autofact path exists (create if it doesn't)
	err := os.MkdirAll(autofactPath, 0760)
	if err != nil {
		fmt.Fprintf(os.Stderr, "unable to create AUTOFACT_PATH: %s\n", err)
		fmt.Fprintln(os.Stderr, "startup error: exiting")
		os.Exit(1)
	}

	// finalize the paths
	connFile = filepath.Join(autofactPath, connFile)

	// process the settings: this gets read first just in case flags override
	var connMsg string
	err = connConf.Load(connFile)
	if err != nil {
		// capture the error for logging once it is setup and continue.  An error
		// is not a show stopper as the file may not exist if this is the first
		// time autofact has run on this node.
		connMsg = fmt.Sprintf("using default connection settings")
	}

	// Parse the flags.
	flag.Parse()

	// now that everything is parsed; set up logging
	SetLogging()
	defer CloseOut()
	// if there was an error reading the connection configuration and this isn't
	// being run serverless, log it
	if connMsg != "" && !serverless {
		log.Warn(
			err.Error(),
			zap.String("op", fmt.Sprintf("load %s", connFile)),
			zap.String("conf", connMsg),
		)
	}

	// TODO add env var support

	// get a client
	c := NewClient(connConf, collectFile)
	c.AutoPath = autofactPath

	// if serverless: load the collection configuration
	if serverless {
		collectFile = filepath.Join(autofactPath, collectFile)
		err = c.Collect.Load(collectFile)
		if err != nil {
			log.Warn(
				err.Error(),
				zap.String("op", fmt.Sprintf("load %s", collectFile)),
				zap.String("conf", "using default collect settings"),
			)
			c.Collect.UseDefaults()
			err = c.Collect.SaveJSON()
			if err != nil {
				log.Warn(
					err.Error(),
					zap.String("op", fmt.Sprintf("save %s", collectFile)),
				)
			}
		}
	}

	// handle signals
	go handleSignals(c)

	// doneCh is used to signal that the connection has been closed
	doneCh := make(chan struct{})

	// Set up the output destination.
	if serverless { // open the datafile to use
		SetDataOut()
		if startInfo { // if system info is collected on startup...
			WriteSystemInfo()
		}
	}

	if !serverless { // connect to the server
		// connect to the Server
		c.ServerURL = url.URL{Scheme: "ws", Host: fmt.Sprintf("%s:%s", c.ServerAddress, c.ServerPort), Path: "/client"}

		// must have a connection before doing anything
		for i := 0; i < 3; i++ {
			connected := c.Connect()
			if connected {
				break
			}
			// retry on fail until retry attempts have been exceeded
		}
		if !c.IsConnected() {
			log.Error(
				"unable to connect",
				zap.String("server", c.ServerURL.String()),
			)
			CloseOut() // defer doesn't run on fatal
			os.Exit(1)
		}
		// if connected, save the conf: this will also save the ClientID
		err = c.Conn.Save()
		if err != nil {
			log.Error(
				err.Error(),
				zap.String("op", "save conn"),
				zap.String("file", c.Conn.Filename),
			)
		}
	}

	// set up the data processing
	if serverless {
		// since there isn't a server pull for healthbeat, a local ticker is started
		go c.HealthbeatLocal(doneCh)
		c.CPUUtilization = c.CPUUtilizationLocal
		c.MemInfo = c.MemInfoLocal
		c.NetUsage = c.NetUsageLocal
	} else {
		// assign the
		c.LoadAvg = LoadAvgFB
		c.CPUUtilization = c.CPUUtilizationFB
		c.MemInfo = c.MemInfoFB
		c.NetUsage = c.NetUsageFB

		// start the listener
		go c.Listen(doneCh)
		// start the message writer
		go c.MessageWriter(doneCh)
	}

	go c.CPUUtilization(doneCh)
	go c.MemInfo(doneCh)
	go c.NetUsage(doneCh)

	<-doneCh
}

func SetLogging() {
	// if logfile is empty, use Stderr
	var err error
	if logOut == "" || logOut == "stderr" {
		logFile = os.Stderr
		goto newLog
	}
	if logOut == "stdout" {
		logFile = os.Stdout
		goto newLog
	}
	logFile, err = os.OpenFile(logOut, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0664)
	if err != nil {
		panic(err)
	}
newLog:
	log = zap.New(
		zap.NewJSONEncoder(
			zap.RFC3339Formatter("ts"),
		),
		zap.Output(logFile),
	)
	log.SetLevel(*loglevel)
}

func SetDataOut() {
	var err error
	if dataOut == "" || dataOut == "stdout" {
		dataFile = os.Stdout
		goto newData
	}
	if dataOut == "stderr" {
		dataFile = os.Stderr
		goto newData
	}
	dataFile, err = os.OpenFile(dataOut, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0664)
	if err != nil {
		log.Fatal(
			err.Error(),
			zap.String("op", "open datafile"),
			zap.String("filename", dataOut),
		)
	}
newData:
	data = czap.New(
		czap.NewJSONEncoder(
			czap.RFC3339Formatter("ts"),
		),
		czap.Output(dataFile),
	)
	data.SetLevel(czap.WarnLevel)
}

// CloseOut closes the local output destinations before shutdown.
func CloseOut() {
	if logFile != nil {
		logFile.Close()
	}
	// If running serverless, close the data file.
	if serverless {
		dataFile.Close()
	}
}

func handleSignals(c *Client) {
	ch := make(chan os.Signal, 1)
	signal.Notify(ch, os.Interrupt)
	v := <-ch
	log.Info(
		"os signal received: shutting down autofact",
		zap.Object("signal", v.String()),
	)
	// If there's a connection send a close signal
	if c.IsConnected() {
		log.Debug(
			"closing connection",
			zap.String("op", "shutdown"),
		)
		c.WS.WriteMessage(websocket.CloseMessage, []byte(string(c.Conn.ID)+" shutting down"))
	}
	CloseOut()

	os.Exit(1)
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"github.com/facebookgo/inject"
	"github.com/labstack/gommon/log"
	"github.com/photoshelf/photoshelf-storage/application/service"
	"github.com/photoshelf/photoshelf-storage/infrastructure/datastore"
	"github.com/photoshelf/photoshelf-storage/model"
	"github.com/photoshelf/photoshelf-storage/presentation/controller"
	"gopkg.in/yaml.v2"
	"io/ioutil"
)

type Configuration struct {
	Server struct {
		Port int
	}
	Storage struct {
		Type string
		Path string
	}
}

func (configuration *Configuration) parse() {
	configuration.Server.Port = *flag.Int("p", configuration.Server.Port, "port number")
	configuration.Storage.Type = *flag.String("t", configuration.Storage.Type, "storage type [file|leveldb|boltdb]")
	configuration.Storage.Path = *flag.String("d", configuration.Storage.Path, "storage path")
	flag.Parse()
}

func configure() (*Configuration, error) {
	configurationFile, err := ioutil.ReadFile("./application.yml")
	if err != nil {
		log.Warn(err)
	}

	configuration := &Configuration{}
	if err := yaml.Unmarshal(configurationFile, configuration); err != nil {
		return nil, err
	}
	configuration.parse()

	var repository model.Repository
	switch configuration.Storage.Type {
	case "file":
		repository = datastore.NewFileStorage(configuration.Storage.Type)
	case "leveldb":
		repository, err = datastore.NewLeveldbStorage(configuration.Storage.Type)
		if err != nil {
			return nil, err
		}
	case "boltdb":
		repository, err = datastore.NewBoltdbStorage(configuration.Storage.Type)
		if err != nil {
			return nil, err
		}
	default:
		return nil, errors.New(fmt.Sprintf("unknown storage type : %s", configuration.Storage.Type))
	}

	photoController := new(controller.PhotoController)
	if err := inject.Populate(photoController, new(service.PhotoService), repository); err != nil {
		return nil, err
	}

	return configuration, nil
}
<commit_msg>Fix storage path<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"github.com/facebookgo/inject"
	"github.com/labstack/gommon/log"
	"github.com/photoshelf/photoshelf-storage/application/service"
	"github.com/photoshelf/photoshelf-storage/infrastructure/datastore"
	"github.com/photoshelf/photoshelf-storage/model"
	"github.com/photoshelf/photoshelf-storage/presentation/controller"
	"gopkg.in/yaml.v2"
	"io/ioutil"
)

type Configuration struct {
	Server struct {
		Port int
	}
	Storage struct {
		Type string
		Path string
	}
}

func (configuration *Configuration) parse() {
	configuration.Server.Port = *flag.Int("p", configuration.Server.Port, "port number")
	configuration.Storage.Type = *flag.String("t", configuration.Storage.Type, "storage type [file|leveldb|boltdb]")
	configuration.Storage.Path = *flag.String("d", configuration.Storage.Path, "storage path")
	flag.Parse()
}

func configure() (*Configuration, error) {
	configurationFile, err := ioutil.ReadFile("./application.yml")
	if err != nil {
		log.Warn(err)
	}

	configuration := &Configuration{}
	if err := yaml.Unmarshal(configurationFile, configuration); err != nil {
		return nil, err
	}
	configuration.parse()

	var repository model.Repository
	switch configuration.Storage.Type {
	case "file":
		repository = datastore.NewFileStorage(configuration.Storage.Path)
	case "leveldb":
		repository, err = datastore.NewLeveldbStorage(configuration.Storage.Path)
		if err != nil {
			return nil, err
		}
	case "boltdb":
		repository, err = datastore.NewBoltdbStorage(configuration.Storage.Path)
		if err != nil {
			return nil, err
		}
	default:
		return nil, errors.New(fmt.Sprintf("unknown storage type : %s", configuration.Storage.Type))
	}

	photoController := new(controller.PhotoController)
	if err := inject.Populate(photoController, new(service.PhotoService), repository); err != nil {
		return nil, err
	}

	return configuration, nil
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"github.com/drud/ddev/pkg/ddevapp"
	"github.com/drud/ddev/pkg/dockerutil"
	"github.com/drud/ddev/pkg/fileutil"
	"github.com/drud/ddev/pkg/globalconfig"
	"github.com/drud/ddev/pkg/output"
	"github.com/drud/ddev/pkg/updatecheck"
	"github.com/drud/ddev/pkg/util"
	"github.com/drud/ddev/pkg/versionconstants"
	"github.com/mitchellh/go-homedir"
	"github.com/rogpeppe/go-internal/semver"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"gopkg.in/segmentio/analytics-go.v3"
	"os"
	"path/filepath"

	"time"
)

var (
	updateInterval     = time.Hour * 24 * 7 // One week interval between updates
	serviceType        string
	updateDocURL       = "https://ddev.readthedocs.io/en/stable/users/install/"
	instrumentationApp *ddevapp.DdevApp
)

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "ddev",
	Short: "DDEV-Local local development environment",
	Long: `Create and maintain a local web development environment.
Docs: https://ddev.readthedocs.io
Support: https://ddev.readthedocs.io/en/stable/users/support`,
	Version: versionconstants.DdevVersion,
	PersistentPreRun: func(cmd *cobra.Command, args []string) {
		command := os.Args[1]

		// LogSetup() has already been done, but now needs to be done
		// again *after* --json flag is parsed.
		output.LogSetUp()

		// Skip docker and other validation for most commands
		if command != "start" && command != "restart" {
			return
		}

		err := dockerutil.CheckDockerVersion(dockerutil.DockerVersionConstraint)
		if err != nil {
			if err.Error() == "no docker" {
				if os.Args[1] != "version" {
					util.Failed("Could not connect to docker. Please ensure Docker is installed and running.")
				}
			} else {
				util.Warning("The docker version currently installed does not seem to meet ddev's requirements: %v", err)
			}
		}

		updateFile := filepath.Join(globalconfig.GetGlobalDdevDir(), ".update")

		// Do periodic detection of whether an update is available for ddev users.
		timeToCheckForUpdates, err := updatecheck.IsUpdateNeeded(updateFile, updateInterval)
		if err != nil {
			util.Warning("Could not perform update check: %v", err)
		}

		if timeToCheckForUpdates && globalconfig.IsInternetActive() {
			// Recreate the updatefile with current time so we won't do this again soon.
			err = updatecheck.ResetUpdateTime(updateFile)
			if err != nil {
				util.Warning("Failed to update updatecheck file %s", updateFile)
				return // Do not continue as we'll end up with github api violations.
			}

			updateNeeded, updateVersion, updateURL, err := updatecheck.AvailableUpdates("drud", "ddev", versionconstants.DdevVersion)

			if err != nil {
				util.Warning("Could not check for updates. This is most often caused by a networking issue.")
				return
			}

			if updateNeeded {
				output.UserOut.Printf(util.ColorizeText(fmt.Sprintf("\n\nUpgraded DDEV %s is available!\nPlease visit %s to get the upgrade.\nFor upgrade help see %s\n\n", updateVersion, updateURL, updateDocURL), "green"))
			}
		}
	},
	PersistentPostRun: func(cmd *cobra.Command, args []string) {
		// Do not report these commands
		ignores := map[string]bool{"describe": true, "auth": true, "blackfire": false, "clean": true, "composer": true, "debug": true, "delete": true, "drush": true, "exec": true, "export-db": true, "get": true, "help": true, "hostname": true, "import-db": true, "import-files": true, "list": true, "logs": true, "mutagen": true, "mysql": true, "npm": true, "nvm": true, "pause": true, "php": true, "poweroff": true, "pull": true, "push": true, "service": true, "share": true, "snapshot": true, "ssh": true, "stop": true, "version": true, "xdebug": true, "xhprof": true, "yarn": true}

		if _, ok := ignores[cmd.CalledAs()]; ok {
			return
		}
		instrumentationNotSetUpWarning()

		// All this nonsense is to capture the official usage we used for this command.
		// Unfortunately cobra doesn't seem to provide this easily.
		// We use the first word of Use: to get it.
		cmdCopy := cmd
		var fullCommand = make([]string, 0)
		fullCommand = append(fullCommand, util.GetFirstWord(cmdCopy.Use))
		for cmdCopy.HasParent() {
			fullCommand = append(fullCommand, util.GetFirstWord(cmdCopy.Parent().Use))
			cmdCopy = cmdCopy.Parent()
		}
		for i := 0; i < len(fullCommand)/2; i++ {
			j := len(fullCommand) - i - 1
			fullCommand[i], fullCommand[j] = fullCommand[j], fullCommand[i]
		}

		event := ""
		if len(fullCommand) > 1 {
			event = fullCommand[1]
		}

		if globalconfig.DdevGlobalConfig.InstrumentationOptIn && versionconstants.SegmentKey != "" && globalconfig.IsInternetActive() && len(fullCommand) > 1 {
			runTime := util.TimeTrack(time.Now(), "Instrumentation")
			// Try to get default instrumentationApp from current directory if not already set
			if instrumentationApp == nil {
				app, err := ddevapp.NewApp("", false)
				if err == nil {
					instrumentationApp = app
				}
			}
			// If it has been set, provide the tags, otherwise no app tags
			if instrumentationApp != nil {
				instrumentationApp.SetInstrumentationAppTags()
			}
			ddevapp.SetInstrumentationBaseTags()
			ddevapp.SendInstrumentationEvents(event)
			runTime()
		}
	},
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	// bind flags to viper config values...allows override by flag
	viper.AutomaticEnv() // read in environment variables that match

	if err := RootCmd.Execute(); err != nil {
		os.Exit(-1)
	}
}

func init() {

	RootCmd.PersistentFlags().BoolVarP(&output.JSONOutput, "json-output", "j", false, "If true, user-oriented output will be in JSON format.")

	output.LogSetUp()

	// Determine if Docker is running by getting the version.
	// This helps to prevent a user from seeing the Cobra error: "Error: unknown command "<custom command>" for ddev"
	_, err := dockerutil.GetDockerVersion()
	// ddev --version may be called without docker available.
	if err != nil && len(os.Args) > 1 && os.Args[1] != "--version" {
		util.Failed("Could not connect to a docker provider. Please start or install a docker provider.\nFor install help go to: https://ddev.readthedocs.io/en/latest/users/install/")
	}

	// Populate custom/script commands so they're visible
	// We really don't want ~/.ddev or .ddev/homeadditions or .ddev/.globalcommands to have root ownership, breaks things.
	if os.Geteuid() == 0 {
		util.Warning("Not populating custom commands or hostadditions because running with root privileges")
	} else {
		err := ddevapp.PopulateExamplesCommandsHomeadditions("")
		if err != nil {
			util.Warning("populateExamplesAndCommands() failed: %v", err)
		}

		err = addCustomCommands(RootCmd)
		if err != nil {
			util.Warning("Adding custom/shell commands failed: %v", err)
		}
	}
}

func instrumentationNotSetUpWarning() {
	if !output.JSONOutput && versionconstants.SegmentKey == "" && globalconfig.DdevGlobalConfig.InstrumentationOptIn {
		util.Warning("Instrumentation is opted in, but SegmentKey is not available. This usually means you have a locally-built ddev binary or one from a PR build. It's not an error. Please report it if you're using an official release build.")
	}
}

// checkDdevVersionAndOptInInstrumentation() reads global config and checks to see if current version is different
// from the last saved version. If it is, prompt to request anon ddev usage stats
// and update the info.
func checkDdevVersionAndOptInInstrumentation(skipConfirmation bool) error {
	if !output.JSONOutput && semver.Compare(versionconstants.DdevVersion, globalconfig.DdevGlobalConfig.LastStartedVersion) > 0 && globalconfig.DdevGlobalConfig.InstrumentationOptIn == false && !globalconfig.DdevNoInstrumentation && !skipConfirmation {
		allowStats := util.Confirm("It looks like you have a new ddev release.\nMay we send anonymous ddev usage statistics and errors?\nTo know what we will see please take a look at\nhttps://ddev.readthedocs.io/en/stable/users/details/opting-in\nPermission to beam up?")
		if allowStats {
			globalconfig.DdevGlobalConfig.InstrumentationOptIn = true
			client, _ := analytics.NewWithConfig(versionconstants.SegmentKey, analytics.Config{
				Logger: &ddevapp.SegmentNoopLogger{},
			})
			defer func() {
				_ = client.Close()
			}()

			err := ddevapp.SegmentUser(client, ddevapp.GetInstrumentationUser())
			if err != nil {
				output.UserOut.Debugf("error in SegmentUser: %v", err)
			}
		}
	}
	if globalconfig.DdevGlobalConfig.LastStartedVersion != versionconstants.DdevVersion && !skipConfirmation {

		// If they have a new version (but not first-timer) then prompt to poweroff
		if globalconfig.DdevGlobalConfig.LastStartedVersion != "v0.0" {
			output.UserOut.Print("Congratulations, you seem to have a new DDEV version.")
			home, _ := homedir.Dir()
			if globalconfig.DdevGlobalConfig.MutagenEnabledGlobal && fileutil.IsDirectory(filepath.Join(home, ".mutagen")) {
				output.UserOut.Print("Please note that the global ~/.mutagen folder is no longer used by DDEV so you can delete it if it's no longer used by other applications.")
			}
			okPoweroff := util.Confirm("It looks like you have a new DDEV version. During an upgrade it's important to `ddev poweroff`. May I do `ddev poweroff` before continuing? This does no harm and loses no data.")
			if okPoweroff {
				ddevapp.PowerOff()
			}
		}

		// If they have a new version write the new version into last-started
		globalconfig.DdevGlobalConfig.LastStartedVersion = versionconstants.DdevVersion
		err := globalconfig.WriteGlobalConfig(globalconfig.DdevGlobalConfig)
		if err != nil {
			return err
		}

		return nil
	}

	return nil
}
<commit_msg>Clean up messaging on new ddev version (#4232) [skip ci]<commit_after>package cmd

import (
	"fmt"
	"github.com/drud/ddev/pkg/ddevapp"
	"github.com/drud/ddev/pkg/dockerutil"
	"github.com/drud/ddev/pkg/globalconfig"
	"github.com/drud/ddev/pkg/output"
	"github.com/drud/ddev/pkg/updatecheck"
	"github.com/drud/ddev/pkg/util"
	"github.com/drud/ddev/pkg/versionconstants"
	"github.com/rogpeppe/go-internal/semver"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"gopkg.in/segmentio/analytics-go.v3"
	"os"
	"path/filepath"

	"time"
)

var (
	updateInterval     = time.Hour * 24 * 7 // One week interval between updates
	serviceType        string
	updateDocURL       = "https://ddev.readthedocs.io/en/stable/users/install/"
	instrumentationApp *ddevapp.DdevApp
)

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "ddev",
	Short: "DDEV-Local local development environment",
	Long: `Create and maintain a local web development environment.
Docs: https://ddev.readthedocs.io
Support: https://ddev.readthedocs.io/en/stable/users/support`,
	Version: versionconstants.DdevVersion,
	PersistentPreRun: func(cmd *cobra.Command, args []string) {
		command := os.Args[1]

		// LogSetup() has already been done, but now needs to be done
		// again *after* --json flag is parsed.
		output.LogSetUp()

		// Skip docker and other validation for most commands
		if command != "start" && command != "restart" {
			return
		}

		err := dockerutil.CheckDockerVersion(dockerutil.DockerVersionConstraint)
		if err != nil {
			if err.Error() == "no docker" {
				if os.Args[1] != "version" {
					util.Failed("Could not connect to docker. Please ensure Docker is installed and running.")
				}
			} else {
				util.Warning("The docker version currently installed does not seem to meet ddev's requirements: %v", err)
			}
		}

		updateFile := filepath.Join(globalconfig.GetGlobalDdevDir(), ".update")

		// Do periodic detection of whether an update is available for ddev users.
		timeToCheckForUpdates, err := updatecheck.IsUpdateNeeded(updateFile, updateInterval)
		if err != nil {
			util.Warning("Could not perform update check: %v", err)
		}

		if timeToCheckForUpdates && globalconfig.IsInternetActive() {
			// Recreate the updatefile with current time so we won't do this again soon.
			err = updatecheck.ResetUpdateTime(updateFile)
			if err != nil {
				util.Warning("Failed to update updatecheck file %s", updateFile)
				return // Do not continue as we'll end up with github api violations.
			}

			updateNeeded, updateVersion, updateURL, err := updatecheck.AvailableUpdates("drud", "ddev", versionconstants.DdevVersion)

			if err != nil {
				util.Warning("Could not check for updates. This is most often caused by a networking issue.")
				return
			}

			if updateNeeded {
				output.UserOut.Printf(util.ColorizeText(fmt.Sprintf("\n\nUpgraded DDEV %s is available!\nPlease visit %s to get the upgrade.\nFor upgrade help see %s\n\n", updateVersion, updateURL, updateDocURL), "green"))
			}
		}
	},
	PersistentPostRun: func(cmd *cobra.Command, args []string) {
		// Do not report these commands
		ignores := map[string]bool{"describe": true, "auth": true, "blackfire": false, "clean": true, "composer": true, "debug": true, "delete": true, "drush": true, "exec": true, "export-db": true, "get": true, "help": true, "hostname": true, "import-db": true, "import-files": true, "list": true, "logs": true, "mutagen": true, "mysql": true, "npm": true, "nvm": true, "pause": true, "php": true, "poweroff": true, "pull": true, "push": true, "service": true, "share": true, "snapshot": true, "ssh": true, "stop": true, "version": true, "xdebug": true, "xhprof": true, "yarn": true}

		if _, ok := ignores[cmd.CalledAs()]; ok {
			return
		}
		instrumentationNotSetUpWarning()

		// All this nonsense is to capture the official usage we used for this command.
		// Unfortunately cobra doesn't seem to provide this easily.
		// We use the first word of Use: to get it.
		cmdCopy := cmd
		var fullCommand = make([]string, 0)
		fullCommand = append(fullCommand, util.GetFirstWord(cmdCopy.Use))
		for cmdCopy.HasParent() {
			fullCommand = append(fullCommand, util.GetFirstWord(cmdCopy.Parent().Use))
			cmdCopy = cmdCopy.Parent()
		}
		for i := 0; i < len(fullCommand)/2; i++ {
			j := len(fullCommand) - i - 1
			fullCommand[i], fullCommand[j] = fullCommand[j], fullCommand[i]
		}

		event := ""
		if len(fullCommand) > 1 {
			event = fullCommand[1]
		}

		if globalconfig.DdevGlobalConfig.InstrumentationOptIn && versionconstants.SegmentKey != "" && globalconfig.IsInternetActive() && len(fullCommand) > 1 {
			runTime := util.TimeTrack(time.Now(), "Instrumentation")
			// Try to get default instrumentationApp from current directory if not already set
			if instrumentationApp == nil {
				app, err := ddevapp.NewApp("", false)
				if err == nil {
					instrumentationApp = app
				}
			}
			// If it has been set, provide the tags, otherwise no app tags
			if instrumentationApp != nil {
				instrumentationApp.SetInstrumentationAppTags()
			}
			ddevapp.SetInstrumentationBaseTags()
			ddevapp.SendInstrumentationEvents(event)
			runTime()
		}
	},
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	// bind flags to viper config values...allows override by flag
	viper.AutomaticEnv() // read in environment variables that match

	if err := RootCmd.Execute(); err != nil {
		os.Exit(-1)
	}
}

func init() {

	RootCmd.PersistentFlags().BoolVarP(&output.JSONOutput, "json-output", "j", false, "If true, user-oriented output will be in JSON format.")

	output.LogSetUp()

	// Determine if Docker is running by getting the version.
	// This helps to prevent a user from seeing the Cobra error: "Error: unknown command "<custom command>" for ddev"
	_, err := dockerutil.GetDockerVersion()
	// ddev --version may be called without docker available.
	if err != nil && len(os.Args) > 1 && os.Args[1] != "--version" {
		util.Failed("Could not connect to a docker provider. Please start or install a docker provider.\nFor install help go to: https://ddev.readthedocs.io/en/latest/users/install/")
	}

	// Populate custom/script commands so they're visible
	// We really don't want ~/.ddev or .ddev/homeadditions or .ddev/.globalcommands to have root ownership, breaks things.
	if os.Geteuid() == 0 {
		util.Warning("Not populating custom commands or hostadditions because running with root privileges")
	} else {
		err := ddevapp.PopulateExamplesCommandsHomeadditions("")
		if err != nil {
			util.Warning("populateExamplesAndCommands() failed: %v", err)
		}

		err = addCustomCommands(RootCmd)
		if err != nil {
			util.Warning("Adding custom/shell commands failed: %v", err)
		}
	}
}

func instrumentationNotSetUpWarning() {
	if !output.JSONOutput && versionconstants.SegmentKey == "" && globalconfig.DdevGlobalConfig.InstrumentationOptIn {
		util.Warning("Instrumentation is opted in, but SegmentKey is not available. This usually means you have a locally-built ddev binary or one from a PR build. It's not an error. Please report it if you're using an official release build.")
	}
}

// checkDdevVersionAndOptInInstrumentation() reads global config and checks to see if current version is different
// from the last saved version. If it is, prompt to request anon ddev usage stats
// and update the info.
func checkDdevVersionAndOptInInstrumentation(skipConfirmation bool) error {
	if !output.JSONOutput && semver.Compare(versionconstants.DdevVersion, globalconfig.DdevGlobalConfig.LastStartedVersion) > 0 && globalconfig.DdevGlobalConfig.InstrumentationOptIn == false && !globalconfig.DdevNoInstrumentation && !skipConfirmation {
		allowStats := util.Confirm("It looks like you have a new ddev release.\nMay we send anonymous ddev usage statistics and errors?\nTo know what we will see please take a look at\nhttps://ddev.readthedocs.io/en/stable/users/details/opting-in\nPermission to beam up?")
		if allowStats {
			globalconfig.DdevGlobalConfig.InstrumentationOptIn = true
			client, _ := analytics.NewWithConfig(versionconstants.SegmentKey, analytics.Config{
				Logger: &ddevapp.SegmentNoopLogger{},
			})
			defer func() {
				_ = client.Close()
			}()

			err := ddevapp.SegmentUser(client, ddevapp.GetInstrumentationUser())
			if err != nil {
				output.UserOut.Debugf("error in SegmentUser: %v", err)
			}
		}
	}
	if globalconfig.DdevGlobalConfig.LastStartedVersion != versionconstants.DdevVersion && !skipConfirmation {

		// If they have a new version (but not first-timer) then prompt to poweroff
		if globalconfig.DdevGlobalConfig.LastStartedVersion != "v0.0" {
			output.UserOut.Print("You seem to have a new DDEV version.")
			okPoweroff := util.Confirm("During an upgrade it's important to `ddev poweroff`.\nMay I do `ddev poweroff` before continuing?\nThis does no harm and loses no data.")
			if okPoweroff {
				ddevapp.PowerOff()
			}
		}

		// If they have a new version write the new version into last-started
		globalconfig.DdevGlobalConfig.LastStartedVersion = versionconstants.DdevVersion
		err := globalconfig.WriteGlobalConfig(globalconfig.DdevGlobalConfig)
		if err != nil {
			return err
		}

		return nil
	}

	return nil
}
<|endoftext|>


<commit_before>package main

type InstanceMetadata struct {
	ID         string
	Name       string
	Version    string
	Hostname   string
	Zone       string
	Project    string
	InternalIP string
	ExternalIP string
	LBRequest  string
	ClientIP   string
	Error      string
}

const (
	html = `<!doctype html>

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.0/css/materialize.min.css">

<title>Frontend Web Server</title>

Backend that serviced this request

	  Name
	  {{.Name}}

	  Version
	  {{.Version}}

	  Instance ID
	  {{.ID}}

	  Hostname
	  {{.Hostname}}

	  Zone
	  {{.Zone}}

	  Project
	  {{.Project}}

	  Internal IP
	  {{.InternalIP}}

	  External IP
	  {{.ExternalIP}}

Proxy that handled this request

	  Request Headers

{{.LBRequest}}

		Error
		{{.Error}}

`
)
<commit_msg>Change to blue<commit_after>package main

type InstanceMetadata struct {
	ID         string
	Name       string
	Version    string
	Hostname   string
	Zone       string
	Project    string
	InternalIP string
	ExternalIP string
	LBRequest  string
	ClientIP   string
	Error      string
}

const (
	html = `<!doctype html>

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.0/css/materialize.min.css">

<title>Frontend Web Server</title>

Backend that serviced this request

	  Name
	  {{.Name}}

	  Version
	  {{.Version}}

	  Instance ID
	  {{.ID}}

	  Hostname
	  {{.Hostname}}

	  Zone
	  {{.Zone}}

	  Project
	  {{.Project}}

	  Internal IP
	  {{.InternalIP}}

	  External IP
	  {{.ExternalIP}}

Proxy that handled this request

	  Request Headers

{{.LBRequest}}

		Error
		{{.Error}}

`
)
<|endoftext|>


<commit_before>package main

// Fetch recent CGM readings from a Dexcom G4 receiver,
// with options to upload to Nightscout and update a local JSON file.

import (
	"flag"
	"fmt"
	"log"
	"os"
	"time"

	"github.com/ecc1/dexcom"
	"github.com/ecc1/nightscout"
	"github.com/ecc1/papertrail"
)

type (
	// Entries is an alias, for conciseness.
	Entries = nightscout.Entries
)

const (
	maxClockDelta = 5 * time.Minute
	gapDuration   = 7 * time.Minute
)

var (
	cgmHistory         = flag.Duration("b", 20*time.Minute, "maximum age of CGM entries to fetch")
	sinceFlag          = flag.String("t", "", "get records since the specified `time` in RFC3339 format")
	uploadFlag         = flag.Bool("u", false, "upload to Nightscout")
	simulateUploadFlag = flag.Bool("s", false, "simulate upload to Nightscout")
	verboseFlag        = flag.Bool("v", false, "verbose mode")
	jsonFile           = flag.String("f", "", "append results to JSON `file`")
	jsonCutoff         = flag.Duration("k", 7*24*time.Hour, "maximum age of CGM entries to keep in JSON file")

	cgm        *dexcom.CGM
	cgmTime    time.Time
	cgmEpoch   time.Time
	glucose    dexcom.Records
	cgmRecords dexcom.Records
	oldEntries Entries
	newEntries Entries

	somethingFailed = false
)

func main() {
	flag.Parse()
	if *simulateUploadFlag {
		*uploadFlag = true
	}
	nightscout.SetNoUpload(*simulateUploadFlag)
	nightscout.SetVerbose(*verboseFlag)
	papertrail.StartLogging()
	if *jsonFile != "" {
		oldEntries = readJSON()
	}
	getCGMInfo()
	if *verboseFlag && !*uploadFlag {
		newEntries.Print()
	}
	if *jsonFile != "" {
		updateJSON()
	}
	if *uploadFlag {
		uploadEntries()
	}
	if somethingFailed {
		os.Exit(1)
	}
}

func getCGMInfo() {
	cgm = dexcom.Open()
	cgmTime = checkCGMClock()
	if cgm.Error() != nil {
		log.Fatal(cgm.Error())
	}
	if *sinceFlag != "" {
		var err error
		cgmEpoch, err = time.Parse(dexcom.JSONTimeLayout, *sinceFlag)
		if err != nil {
			log.Fatal(err)
		}
	} else {
		cgmEpoch = cgmTime.Add(-*cgmHistory)
	}
	// Use time of most recent entry to reduce how far back to go.
	if len(oldEntries) != 0 {
		lastTime := oldEntries[0].Time()
		if cgmEpoch.Before(lastTime) {
			cgmEpoch = lastTime
		}
	}
	log.Printf("retrieving records since %s", cgmEpoch.Format(dexcom.UserTimeLayout))
	sensor := cgm.ReadHistory(dexcom.SensorData, cgmEpoch)
	egv := cgm.ReadHistory(dexcom.EGVData, cgmEpoch)
	meter := cgm.ReadHistory(dexcom.MeterData, cgmEpoch)
	cal := cgm.ReadHistory(dexcom.CalibrationData, cgmEpoch)
	if cgm.Error() != nil {
		log.Fatal(cgm.Error())
	}
	glucose = validateGlucose(egv)
	if *verboseFlag {
		log.Printf("%d valid glucose records", len(glucose))
	}
	cgmRecords = dexcom.MergeHistory(sensor, glucose, meter, cal)
	log.Printf("%d CGM records", len(cgmRecords))
	newEntries = discardIncomplete(dexcom.NightscoutEntries(cgmRecords))
	describeEntries(newEntries, "Nightscout")
}

func timeStr(e nightscout.Entry) string {
	return e.Time().Format(dexcom.UserTimeLayout)
}

func describeEntries(v Entries, kind string) {
	n := len(v)
	switch n {
	case 0:
		log.Printf("0 %s entries", kind)
	case 1:
		log.Printf("1 %s entry at %s", kind, timeStr(v[0]))
	default:
		log.Printf("%d %s entries from %s to %s", n, kind, timeStr(v[0]), timeStr(v[n-1]))
	}
}

func validateGlucose(readings dexcom.Records) dexcom.Records {
	valid := make(dexcom.Records, 0, len(readings))
	for _, r := range readings {
		if !dexcom.IsSpecial(r.Glucose()) {
			valid = append(valid, r)
		}
	}
	return valid
}

func uploadEntries() {
	gaps, err := nightscout.Gaps(cgmEpoch, gapDuration)
	if err != nil {
		log.Print(err)
		somethingFailed = true
		return
	}
	if *verboseFlag {
		printGaps(gaps)
	}
	if len(gaps) == 0 {
		log.Printf("no Nightscout gaps")
		return
	}
	missing := nightscout.Missing(newEntries, gaps)
	log.Printf("uploading %d entries to Nightscout", len(missing))
	for _, e := range missing {
		err := nightscout.Upload("POST", "entries", e)
		if err != nil {
			log.Print(err)
			somethingFailed = true
			return
		}
	}
}

// If the most recent glucose entry is incomplete, discard it.
// This can happen if the loop runs at the same time the sensor
// transmits a new reading, or if the sensor is warming up. If we
// simply wait until next time, both EGV and sensor records might be
// available.  If the sensor is warming up, there still won't be a
// matching EGV record, but the raw-only entry will be uploaded
// because it's no longer the most recent.
func discardIncomplete(entries Entries) Entries {
	if len(entries) == 0 {
		return entries
	}
	e := entries[0]
	if e.Type == nightscout.SGVType && (e.SGV == 0 || e.Unfiltered == 0) {
		return entries[1:]
	}
	return entries
}

func checkCGMClock() time.Time {
	t := cgm.ReadDisplayTime()
	if cgm.Error() != nil {
		return t
	}
	delta := time.Until(t)
	if delta < 0 {
		delta = -delta
	}
	log.Printf("CGM clock difference = %v", delta)
	if delta > maxClockDelta {
		cgm.SetError(fmt.Errorf("CGM clock difference is greater than %v", maxClockDelta))
	}
	return t
}

func printGaps(gaps []nightscout.Gap) {
	for _, g := range gaps {
		t1 := g.Start
		t2 := g.Finish
		gap := t2.Sub(t1)
		s1 := t1.Format(dexcom.UserTimeLayout)
		s2 := t2.Format(dexcom.UserTimeLayout)
		log.Printf("%v gap from %s to %s", gap, s1, s2)
	}
}

func readJSON() Entries {
	entries, err := nightscout.ReadEntries(*jsonFile)
	if err != nil && !os.IsNotExist(err) {
		log.Printf("%s: %v", *jsonFile, err)
		somethingFailed = true
		return nil
	}
	log.Printf("read %d entries from %s", len(entries), *jsonFile)
	entries.Sort()
	return entries
}

func updateJSON() {
	log.Printf("merging %d old and %d new entries", len(oldEntries), len(newEntries))
	merged := nightscout.MergeEntries(oldEntries, newEntries)
	describeEntries(merged, "merged")
	cutoff := cgmTime.Add(-*jsonCutoff)
	trimmed := merged.TrimAfter(cutoff)
	describeEntries(trimmed, "trimmed")
	// Back up JSON file with a "~" suffix.
	err := os.Rename(*jsonFile, *jsonFile+"~")
	if err != nil && !os.IsNotExist(err) {
		log.Print(err)
		somethingFailed = true
	}
	err = trimmed.Save(*jsonFile)
	if err != nil {
		log.Print(err)
		somethingFailed = true
	}
	log.Printf("wrote %d entries to %s", len(trimmed), *jsonFile)
}
<commit_msg>Use recent JSON entry to limit CGM retrieval but not NS upload<commit_after>package main

// Fetch recent CGM readings from a Dexcom G4 receiver,
// with options to upload to Nightscout and update a local JSON file.

import (
	"flag"
	"fmt"
	"log"
	"os"
	"time"

	"github.com/ecc1/dexcom"
	"github.com/ecc1/nightscout"
	"github.com/ecc1/papertrail"
)

type (
	// Entries is an alias, for conciseness.
	Entries = nightscout.Entries
)

const (
	maxClockDelta = 5 * time.Minute
	gapDuration   = 7 * time.Minute
)

var (
	cgmHistory         = flag.Duration("b", 20*time.Minute, "maximum age of CGM entries to fetch")
	sinceFlag          = flag.String("t", "", "get records since the specified `time` in RFC3339 format")
	uploadFlag         = flag.Bool("u", false, "upload to Nightscout")
	simulateUploadFlag = flag.Bool("s", false, "simulate upload to Nightscout")
	verboseFlag        = flag.Bool("v", false, "verbose mode")
	jsonFile           = flag.String("f", "", "append results to JSON `file`")
	jsonCutoff         = flag.Duration("k", 7*24*time.Hour, "maximum age of CGM entries to keep in JSON file")

	cgm        *dexcom.CGM
	cgmTime    time.Time
	cgmEpoch   time.Time
	glucose    dexcom.Records
	cgmRecords dexcom.Records
	oldEntries Entries
	newEntries Entries

	somethingFailed = false
)

func main() {
	flag.Parse()
	if *simulateUploadFlag {
		*uploadFlag = true
	}
	nightscout.SetNoUpload(*simulateUploadFlag)
	nightscout.SetVerbose(*verboseFlag)
	papertrail.StartLogging()
	if *jsonFile != "" {
		oldEntries = readJSON()
	}
	getCGMInfo()
	if *verboseFlag && !*uploadFlag {
		newEntries.Print()
	}
	if *jsonFile != "" {
		updateJSON()
	}
	if *uploadFlag {
		uploadEntries()
	}
	if somethingFailed {
		os.Exit(1)
	}
}

func getCGMInfo() {
	cgm = dexcom.Open()
	cgmTime = checkCGMClock()
	if cgm.Error() != nil {
		log.Fatal(cgm.Error())
	}
	if *sinceFlag != "" {
		var err error
		cgmEpoch, err = time.Parse(dexcom.JSONTimeLayout, *sinceFlag)
		if err != nil {
			log.Fatal(err)
		}
	} else {
		cgmEpoch = cgmTime.Add(-*cgmHistory)
	}
	// Use time of most recent entry to reduce how far back to go.
	cutoff := cgmEpoch
	if len(oldEntries) != 0 {
		lastTime := oldEntries[0].Time()
		if cutoff.Before(lastTime) {
			cutoff = lastTime
		}
	}
	log.Printf("retrieving records since %s", cutoff.Format(dexcom.UserTimeLayout))
	sensor := cgm.ReadHistory(dexcom.SensorData, cutoff)
	egv := cgm.ReadHistory(dexcom.EGVData, cutoff)
	meter := cgm.ReadHistory(dexcom.MeterData, cutoff)
	cal := cgm.ReadHistory(dexcom.CalibrationData, cutoff)
	if cgm.Error() != nil {
		log.Fatal(cgm.Error())
	}
	glucose = validateGlucose(egv)
	if *verboseFlag {
		log.Printf("%d valid glucose records", len(glucose))
	}
	cgmRecords = dexcom.MergeHistory(sensor, glucose, meter, cal)
	log.Printf("%d CGM records", len(cgmRecords))
	newEntries = discardIncomplete(dexcom.NightscoutEntries(cgmRecords))
	describeEntries(newEntries, "Nightscout")
}

func timeStr(e nightscout.Entry) string {
	return e.Time().Format(dexcom.UserTimeLayout)
}

func describeEntries(v Entries, kind string) {
	n := len(v)
	switch n {
	case 0:
		log.Printf("0 %s entries", kind)
	case 1:
		log.Printf("1 %s entry at %s", kind, timeStr(v[0]))
	default:
		log.Printf("%d %s entries from %s to %s", n, kind, timeStr(v[0]), timeStr(v[n-1]))
	}
}

func validateGlucose(readings dexcom.Records) dexcom.Records {
	valid := make(dexcom.Records, 0, len(readings))
	for _, r := range readings {
		if !dexcom.IsSpecial(r.Glucose()) {
			valid = append(valid, r)
		}
	}
	return valid
}

func uploadEntries() {
	gaps, err := nightscout.Gaps(cgmEpoch, gapDuration)
	if err != nil {
		log.Print(err)
		somethingFailed = true
		return
	}
	if *verboseFlag {
		printGaps(gaps)
	}
	if len(gaps) == 0 {
		log.Printf("no Nightscout gaps")
		return
	}
	missing := nightscout.Missing(newEntries, gaps)
	log.Printf("uploading %d entries to Nightscout", len(missing))
	for _, e := range missing {
		err := nightscout.Upload("POST", "entries", e)
		if err != nil {
			log.Print(err)
			somethingFailed = true
			return
		}
	}
}

// If the most recent glucose entry is incomplete, discard it.
// This can happen if the loop runs at the same time the sensor
// transmits a new reading, or if the sensor is warming up. If we
// simply wait until next time, both EGV and sensor records might be
// available.  If the sensor is warming up, there still won't be a
// matching EGV record, but the raw-only entry will be uploaded
// because it's no longer the most recent.
func discardIncomplete(entries Entries) Entries {
	if len(entries) == 0 {
		return entries
	}
	e := entries[0]
	if e.Type == nightscout.SGVType && (e.SGV == 0 || e.Unfiltered == 0) {
		return entries[1:]
	}
	return entries
}

func checkCGMClock() time.Time {
	t := cgm.ReadDisplayTime()
	if cgm.Error() != nil {
		return t
	}
	delta := time.Until(t)
	if delta < 0 {
		delta = -delta
	}
	log.Printf("CGM clock difference = %v", delta)
	if delta > maxClockDelta {
		cgm.SetError(fmt.Errorf("CGM clock difference is greater than %v", maxClockDelta))
	}
	return t
}

func printGaps(gaps []nightscout.Gap) {
	for _, g := range gaps {
		t1 := g.Start
		t2 := g.Finish
		gap := t2.Sub(t1)
		s1 := t1.Format(dexcom.UserTimeLayout)
		s2 := t2.Format(dexcom.UserTimeLayout)
		log.Printf("%v gap from %s to %s", gap, s1, s2)
	}
}

func readJSON() Entries {
	entries, err := nightscout.ReadEntries(*jsonFile)
	if err != nil && !os.IsNotExist(err) {
		log.Printf("%s: %v", *jsonFile, err)
		somethingFailed = true
		return nil
	}
	log.Printf("read %d entries from %s", len(entries), *jsonFile)
	entries.Sort()
	return entries
}

func updateJSON() {
	log.Printf("merging %d old and %d new entries", len(oldEntries), len(newEntries))
	merged := nightscout.MergeEntries(oldEntries, newEntries)
	describeEntries(merged, "merged")
	cutoff := cgmTime.Add(-*jsonCutoff)
	trimmed := merged.TrimAfter(cutoff)
	describeEntries(trimmed, "trimmed")
	// Back up JSON file with a "~" suffix.
	err := os.Rename(*jsonFile, *jsonFile+"~")
	if err != nil && !os.IsNotExist(err) {
		log.Print(err)
		somethingFailed = true
	}
	err = trimmed.Save(*jsonFile)
	if err != nil {
		log.Print(err)
		somethingFailed = true
	}
	log.Printf("wrote %d entries to %s", len(trimmed), *jsonFile)
}
<|endoftext|>


<commit_before>package games

import (
	"context"
	"errors"
	"fmt"
	"path/filepath"

	"github.com/danielkrainas/gobag/cmd"

	"github.com/danielkrainas/shex/cmd/cmdutils"
	"github.com/danielkrainas/shex/manager"
	"github.com/danielkrainas/shex/mods"
)

func init() {
	cmd.Register("games", Info)
}

var (
	Info = &cmd.Info{
		Use:   "games",
		Short: "",
		Long:  "",
		SubCommands: []*cmd.Info{
			{
				Use:   "add",
				Short: "add a game folder",
				Long:  "add a game folder",
				Run:   cmd.ExecutorFunc(addGame),
			},

			{
				Use:   "remove",
				Short: "remove a game folder",
				Long:  "remove a game folder",
				Run:   cmd.ExecutorFunc(removeGame),
			},
			{
				Use:   "list",
				Short: "list games",
				Long:  "list games",
				Run:   cmd.ExecutorFunc(listGames),
			},
		},
	}
)

/* Add Game Command */
func addGame(ctx context.Context, args []string) error {
	m, err := cmdutils.LoadManager(ctx)
	if err != nil {
		return err
	}

	if len(args) < 1 {
		return errors.New("invalid game path")
	}

	alias := args[0]
	var gamePath string
	if len(args) < 2 {
		gamePath = alias
		alias = manager.DefaultGameName
		fmt.Println(`No alias specified, assuming "default"`)
	} else {
		gamePath, err = filepath.Abs(args[1])
		if err != nil {
			return errors.New("couldn't resolve path: " + args[1])
		}
	}

	if err := m.AddGame(alias, mods.GameDir(gamePath)); err != nil {
		fmt.Printf("error adding game: %v", err)
		return nil
	}

	if err := m.SaveConfig(); err != nil {
		fmt.Printf("error saving config: %v", err)
		return nil
	}

	fmt.Printf("added %s as %q", gamePath, alias)
	return nil
}

/* Remove Game Command */
func removeGame(ctx context.Context, args []string) error {
	if len(args) < 0 {
		return errors.New("you must specify a game alias")
	}

	m, err := cmdutils.LoadManager(ctx)
	if err != nil {
		return err
	}

	alias := args[0]
	if err := m.RemoveGame(alias); err != nil {
		fmt.Printf("error removing game: %v", err)
		return nil
	}

	if err := m.SaveConfig(); err != nil {
		fmt.Printf("error saving config: %v", err)
		return nil
	}

	fmt.Printf("game removed: %s", alias)
	return nil
}

/* List Games Command */
func listGames(ctx context.Context, _ []string) error {
	m, err := cmdutils.LoadManager(ctx)
	if err != nil {
		return err
	}

	if m.Config().Games.Len() < 1 {
		fmt.Printf("no games found.\n")
		return nil
	}

	fmt.Printf("%12s   %s\n", "ALIAS", "FOLDER")
	for alias, gameFolder := range m.Config().Games {
		fmt.Printf("%12s   %s\n", alias, gameFolder)
	}

	return nil
}
<commit_msg>update help for games command<commit_after>package games

import (
	"context"
	"errors"
	"fmt"
	"path/filepath"

	"github.com/danielkrainas/gobag/cmd"

	"github.com/danielkrainas/shex/cmd/cmdutils"
	"github.com/danielkrainas/shex/manager"
	"github.com/danielkrainas/shex/mods"
)

func init() {
	cmd.Register("games", Info)
}

var (
	Info = &cmd.Info{
		Use:   "games",
		Short: "game folder operations",
		Long:  "Perform operations on game folders.",
		SubCommands: []*cmd.Info{
			{
				Use:   "add <name> <path>",
				Short: "add a game folder",
				Long:  "Add the game folder at <path> with the name <name>",
				Run:   cmd.ExecutorFunc(addGame),
			},

			{
				Use:   "remove <name>",
				Short: "remove a game folder",
				Long:  "Remove the game folder with the name <name>",
				Run:   cmd.ExecutorFunc(removeGame),
			},
			{
				Use:   "list",
				Short: "list available game folders",
				Long:  "List available game folders.",
				Run:   cmd.ExecutorFunc(listGames),
			},
		},
	}
)

/* Add Game Command */
func addGame(ctx context.Context, args []string) error {
	m, err := cmdutils.LoadManager(ctx)
	if err != nil {
		return err
	}

	if len(args) < 1 {
		return errors.New("invalid game path")
	}

	alias := args[0]
	var gamePath string
	if len(args) < 2 {
		gamePath = alias
		alias = manager.DefaultGameName
		fmt.Println(`No alias specified, assuming "default"`)
	} else {
		gamePath, err = filepath.Abs(args[1])
		if err != nil {
			return errors.New("couldn't resolve path: " + args[1])
		}
	}

	if err := m.AddGame(alias, mods.GameDir(gamePath)); err != nil {
		fmt.Printf("error adding game: %v", err)
		return nil
	}

	if err := m.SaveConfig(); err != nil {
		fmt.Printf("error saving config: %v", err)
		return nil
	}

	fmt.Printf("added %s as %q", gamePath, alias)
	return nil
}

/* Remove Game Command */
func removeGame(ctx context.Context, args []string) error {
	if len(args) < 0 {
		return errors.New("you must specify a game alias")
	}

	m, err := cmdutils.LoadManager(ctx)
	if err != nil {
		return err
	}

	alias := args[0]
	if err := m.RemoveGame(alias); err != nil {
		fmt.Printf("error removing game: %v", err)
		return nil
	}

	if err := m.SaveConfig(); err != nil {
		fmt.Printf("error saving config: %v", err)
		return nil
	}

	fmt.Printf("game removed: %s", alias)
	return nil
}

/* List Games Command */
func listGames(ctx context.Context, _ []string) error {
	m, err := cmdutils.LoadManager(ctx)
	if err != nil {
		return err
	}

	if m.Config().Games.Len() < 1 {
		fmt.Printf("no games found.\n")
		return nil
	}

	fmt.Printf("%12s   %s\n", "ALIAS", "FOLDER")
	for alias, gameFolder := range m.Config().Games {
		fmt.Printf("%12s   %s\n", alias, gameFolder)
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2013, 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package main

import (
	"fmt"
	"io"

	"github.com/juju/loggo"
	"launchpad.net/gnuflag"

	"launchpad.net/juju-core/cmd"
	"launchpad.net/juju-core/cmd/envcmd"
	"launchpad.net/juju-core/errors"
	"launchpad.net/juju-core/juju"
	"launchpad.net/juju-core/state/api"
)

type DebugLogCommand struct {
	envcmd.EnvCommandBase

	level  string
	params api.DebugLogParams
}

var DefaultLogLocation = "/var/log/juju/all-machines.log"

// defaultLineCount is the default number of lines to
// display, from the end of the consolidated log.
const defaultLineCount = 10

const debuglogDoc = `
Stream the consolidated debug log file. This file contains the log messages
from all nodes in the environment.
`

func (c *DebugLogCommand) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "debug-log",
		Purpose: "display the consolidated log file",
		Doc:     debuglogDoc,
	}
}

func (c *DebugLogCommand) SetFlags(f *gnuflag.FlagSet) {
	c.EnvCommandBase.SetFlags(f)

	f.Var(cmd.NewAppendStringsValue(&c.params.IncludeEntity), "i", "only show log messages for these entities")
	f.Var(cmd.NewAppendStringsValue(&c.params.IncludeEntity), "include", "only show log messages for these entities")
	f.Var(cmd.NewAppendStringsValue(&c.params.ExcludeEntity), "x", "only show log messages for these entities")
	f.Var(cmd.NewAppendStringsValue(&c.params.ExcludeEntity), "exclude", "only show log messages for these entities")
	f.Var(cmd.NewAppendStringsValue(&c.params.IncludeModule), "include-module", "only show log messages for these logging modules")
	f.Var(cmd.NewAppendStringsValue(&c.params.ExcludeModule), "exclude-module", "do not show log messages for these logging modules")

	f.StringVar(&c.level, "l", "", "log level to show, one of [TRACE, DEBUG, INFO, WARNING, ERROR]")
	f.StringVar(&c.level, "level", "", "")

	f.UintVar(&c.params.Backlog, "n", defaultLineCount, "go back this many lines from the end before starting to filter")
	f.UintVar(&c.params.Backlog, "lines", defaultLineCount, "")
	f.UintVar(&c.params.Limit, "limit", 0, "show at most this many lines")
	f.BoolVar(&c.params.Replay, "replay", false, "start filtering from the start")
}

func (c *DebugLogCommand) Init(args []string) error {
	err := c.EnvCommandBase.Init()
	if err != nil {
		return err
	}
	if c.level != "" {
		level, ok := loggo.ParseLevel(c.level)
		if !ok || level < loggo.TRACE || level > loggo.ERROR {
			return fmt.Errorf("level value %q is not one of %q, %q, %q, %q, %q",
				c.level, loggo.TRACE, loggo.DEBUG, loggo.INFO, loggo.WARNING, loggo.ERROR)
		}
		c.params.Level = level
	}
	return cmd.CheckEmpty(args)
}

type DebugLogAPI interface {
	WatchDebugLog(params api.DebugLogParams) (io.ReadCloser, error)
	Close() error
}

var getDebugLogAPI = func(envName string) (DebugLogAPI, error) {
	return juju.NewAPIClientFromName(envName)
}

// Run retrieves the debug log via the API.
func (c *DebugLogCommand) Run(ctx *cmd.Context) (err error) {
	client, err := getDebugLogAPI(c.EnvName)
	if err != nil {
		return err
	}
	defer client.Close()
	debugLog, err := client.WatchDebugLog(c.params)
	if err != nil {
		if errors.IsNotSupportedError(err) {
			return c.watchDebugLog1dot16(ctx)
		}
		return err
	}
	defer debugLog.Close()
	_, err = io.Copy(ctx.Stdout, debugLog)
	return err
}

var runSSHCommand = func(sshCmd *SSHCommand, ctx *cmd.Context) error {
	return sshCmd.Run(ctx)
}

// watchDebugLog1dot16 runs in case of an older API server and uses ssh
// but with server-side grep.
func (c *DebugLogCommand) watchDebugLog1dot16(ctx *cmd.Context) error {
	ctx.Infof("Server does not support new stream log, falling back to tail")
	ctx.Verbosef("filters are not supported with tail")
	sshCmd := &SSHCommand{}
	tailCmd := fmt.Sprintf("tail -n -%d -f %s", c.params.Backlog, DefaultLogLocation)
	// If the api doesn't support WatchDebugLog, then it won't be running in
	// HA either, so machine 0 is where it is all at.
	args := []string{"0", tailCmd}
	err := sshCmd.Init(args)
	if err != nil {
		return err
	}
	sshCmd.EnvName = c.EnvName
	return runSSHCommand(sshCmd, ctx)
}
<commit_msg>Change the 1.16 reference to 1.18.<commit_after>// Copyright 2013, 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package main

import (
	"fmt"
	"io"

	"github.com/juju/loggo"
	"launchpad.net/gnuflag"

	"launchpad.net/juju-core/cmd"
	"launchpad.net/juju-core/cmd/envcmd"
	"launchpad.net/juju-core/errors"
	"launchpad.net/juju-core/juju"
	"launchpad.net/juju-core/state/api"
)

type DebugLogCommand struct {
	envcmd.EnvCommandBase

	level  string
	params api.DebugLogParams
}

var DefaultLogLocation = "/var/log/juju/all-machines.log"

// defaultLineCount is the default number of lines to
// display, from the end of the consolidated log.
const defaultLineCount = 10

const debuglogDoc = `
Stream the consolidated debug log file. This file contains the log messages
from all nodes in the environment.
`

func (c *DebugLogCommand) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "debug-log",
		Purpose: "display the consolidated log file",
		Doc:     debuglogDoc,
	}
}

func (c *DebugLogCommand) SetFlags(f *gnuflag.FlagSet) {
	c.EnvCommandBase.SetFlags(f)

	f.Var(cmd.NewAppendStringsValue(&c.params.IncludeEntity), "i", "only show log messages for these entities")
	f.Var(cmd.NewAppendStringsValue(&c.params.IncludeEntity), "include", "only show log messages for these entities")
	f.Var(cmd.NewAppendStringsValue(&c.params.ExcludeEntity), "x", "only show log messages for these entities")
	f.Var(cmd.NewAppendStringsValue(&c.params.ExcludeEntity), "exclude", "only show log messages for these entities")
	f.Var(cmd.NewAppendStringsValue(&c.params.IncludeModule), "include-module", "only show log messages for these logging modules")
	f.Var(cmd.NewAppendStringsValue(&c.params.ExcludeModule), "exclude-module", "do not show log messages for these logging modules")

	f.StringVar(&c.level, "l", "", "log level to show, one of [TRACE, DEBUG, INFO, WARNING, ERROR]")
	f.StringVar(&c.level, "level", "", "")

	f.UintVar(&c.params.Backlog, "n", defaultLineCount, "go back this many lines from the end before starting to filter")
	f.UintVar(&c.params.Backlog, "lines", defaultLineCount, "")
	f.UintVar(&c.params.Limit, "limit", 0, "show at most this many lines")
	f.BoolVar(&c.params.Replay, "replay", false, "start filtering from the start")
}

func (c *DebugLogCommand) Init(args []string) error {
	err := c.EnvCommandBase.Init()
	if err != nil {
		return err
	}
	if c.level != "" {
		level, ok := loggo.ParseLevel(c.level)
		if !ok || level < loggo.TRACE || level > loggo.ERROR {
			return fmt.Errorf("level value %q is not one of %q, %q, %q, %q, %q",
				c.level, loggo.TRACE, loggo.DEBUG, loggo.INFO, loggo.WARNING, loggo.ERROR)
		}
		c.params.Level = level
	}
	return cmd.CheckEmpty(args)
}

type DebugLogAPI interface {
	WatchDebugLog(params api.DebugLogParams) (io.ReadCloser, error)
	Close() error
}

var getDebugLogAPI = func(envName string) (DebugLogAPI, error) {
	return juju.NewAPIClientFromName(envName)
}

// Run retrieves the debug log via the API.
func (c *DebugLogCommand) Run(ctx *cmd.Context) (err error) {
	client, err := getDebugLogAPI(c.EnvName)
	if err != nil {
		return err
	}
	defer client.Close()
	debugLog, err := client.WatchDebugLog(c.params)
	if err != nil {
		if errors.IsNotSupportedError(err) {
			return c.watchDebugLog1dot18(ctx)
		}
		return err
	}
	defer debugLog.Close()
	_, err = io.Copy(ctx.Stdout, debugLog)
	return err
}

var runSSHCommand = func(sshCmd *SSHCommand, ctx *cmd.Context) error {
	return sshCmd.Run(ctx)
}

// watchDebugLog1dot18 runs in case of an older API server and uses ssh
// but with server-side grep.
func (c *DebugLogCommand) watchDebugLog1dot18(ctx *cmd.Context) error {
	ctx.Infof("Server does not support new stream log, falling back to tail")
	ctx.Verbosef("filters are not supported with tail")
	sshCmd := &SSHCommand{}
	tailCmd := fmt.Sprintf("tail -n -%d -f %s", c.params.Backlog, DefaultLogLocation)
	// If the api doesn't support WatchDebugLog, then it won't be running in
	// HA either, so machine 0 is where it is all at.
	args := []string{"0", tailCmd}
	err := sshCmd.Init(args)
	if err != nil {
		return err
	}
	sshCmd.EnvName = c.EnvName
	return runSSHCommand(sshCmd, ctx)
}
<|endoftext|>