<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"github.com/reducedb/bloom"
	"github.com/reducedb/bloom/scalable"

	// "crypto/sha1"
	// "github.com/spaolacci/murmur3"
	// "github.com/zhenjl/cityhash"

	"log"
	"os"
	"time"
)

var (
	intersection = flag.Bool("i", false, "calculate the intersection")
	diff         = flag.Bool("d", false, "calculate the difference")
	union        = flag.Bool("u", false, "calculate the union")

	blooms = flag.Uint("blooms", 1, "number of bloom filters to use")

	// buffered io
	stdout = bufio.NewWriterSize(os.Stdout, 4096)

	// unique filter
	unique_set bloom.Bloom

	// total tokens in output
	total uint64
)

func main() {

	start := time.Now()

	defer func() {
		stdout.Flush()
		fmt.Fprintln(os.Stderr, "** Token Report **")
		fmt.Fprintln(os.Stderr, "Tokens output: ", total)
		fmt.Fprintln(os.Stderr, "Total time: ", time.Since(start))
	}()

	flag.Parse()

	file_paths := flag.Args()

	unique_set = NewScalableBloom(*blooms)

	// may omit entries due to false positives
	// todo(jason): try crypto hash or use dual filters
	if *union {

		for _, file_path := range file_paths {

			file, err := os.Open(file_path)
			if err != nil {
				log.Fatal(err)
			}

			scanner := bufio.NewScanner(file)

			for scanner.Scan() {
				token := scanner.Bytes()
				if !unique_set.Check(token) {
					stdout.Write(token)
					stdout.WriteByte('\n')
					total++
					unique_set.Add(token)
				}
			}

			file.Close()

		}

		return
	}

	// multi file handling below
	sets := make([]bloom.Bloom, len(file_paths))

	// may require throttling due to disk thrashing
	// initial scan to fill the bloom filters
	for i, file_path := range file_paths {

		set := NewScalableBloom(*blooms)

		file, err := os.Open(file_path)
		if err != nil {
			log.Fatal(err)
		}

		scanner := bufio.NewScanner(file)

		for scanner.Scan() {
			set.Add(scanner.Bytes())
		}

		file.Close()

		sets[i] = set

	}

	// do the work
	switch {

	// unique set of tokens that exist in all files
	case *intersection:
		for _, file_path := range file_paths {

			file, err := os.Open(file_path)
			if err != nil {
				log.Fatal(err)
			}

			scanner := bufio.NewScanner(file)

		NEXT_TOKEN:
			for scanner.Scan() {
				token := scanner.Bytes()
				for _, set := range sets {
					if !set.Check(token) || unique_set.Check(token) {
						goto NEXT_TOKEN
					}
				}
				stdout.Write(token)
				stdout.WriteByte('\n')
				total++
				unique_set.Add(token)
			}

			file.Close()

		}

	// unique set of tokens not in the intersection
	case *diff:
		for _, file_path := range file_paths {

			file, err := os.Open(file_path)
			if err != nil {
				log.Fatal(err)
			}

			scanner := bufio.NewScanner(file)

			for scanner.Scan() {
				token := scanner.Bytes()
				for _, set := range sets {
					if !set.Check(token) && !unique_set.Check(token) {
						stdout.Write(token)
						stdout.WriteByte('\n')
						total++
						unique_set.Add(token)
					}
				}
			}

			file.Close()

		}
	default:
		fmt.Println("Usage: tt -[i,d,u] file1 file2[ file3..]")
		flag.PrintDefaults()
		os.Exit(1)
	}

}

type (
	Bloomer struct {
		bloom.Bloom
		filters []bloom.Bloom
	}
)

func NewScalableBloom(size uint) bloom.Bloom {

	filters := make([]bloom.Bloom, size)

	for i, _ := range filters {
		filter := scalable.New(4096)
		// filter.SetHasher(adler32.New())
		filter.Reset()
		filters[i] = filter
	}

	return &Bloomer{
		filters: filters,
	}

}

func (b *Bloomer) Add(token []byte) bloom.Bloom {
	token = append(make([]byte, len(token)), token...)
	for _, filter := range b.filters {
		filter.Add(token)
		mash(token)
	}
	return b
}

func (b *Bloomer) Check(token []byte) bool {
	token = append(make([]byte, len(token)), token...)
	for _, filter := range b.filters {
		if !filter.Check(token) {
			return false
		}
		mash(token)
	}
	return true
}

// modifies the underlying structure
func mash(token []byte) {
	for i, c := range token {
		c ^= (20 * c)
		token[i] = c
	}
}
<commit_msg>mappy<commit_after>package main

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

var (
	intersection = flag.Bool("i", false, "calculate the intersection")
	diff         = flag.Bool("d", false, "calculate the difference")
	union        = flag.Bool("u", false, "calculate the union")

	// activate lossy processing
	blooms     = flag.Uint("blooms", 0, "number of bloom filters to use (lossy)")
	mash_bytes = flag.Bool("mash", false, "mash bytes for fewer collisions in bloom filters")

	// buffered io
	stdout = bufio.NewWriterSize(os.Stdout, 4096)

	// total tokens in output
	total uint64
)

func main() {

	start := time.Now()

	defer func() {
		stdout.Flush()
		fmt.Fprintln(os.Stderr, "** Token Report **")
		fmt.Fprintln(os.Stderr, "Tokens output: ", total)
		fmt.Fprintln(os.Stderr, "Total time: ", time.Since(start))
	}()

	flag.Parse()

	if !*intersection && !*diff && !*union {
		fmt.Println("Usage: tt -[i,d,u] [-blooms N [-mash]] file1 file2[ file3..]")
		flag.PrintDefaults()
		os.Exit(1)
	}

	file_paths := flag.Args()

	switch {

	// activate bloom filter solution
	case *blooms > 0:

	// defaults to map solution
	default:

		if *union {

			unique_set := make(map[string]bool)

			for _, file_path := range file_paths {

				file, err := os.Open(file_path)
				if err != nil {
					log.Fatal(err)
				}

				scanner := bufio.NewScanner(file)

				for scanner.Scan() {
					token := scanner.Text()
					if _, exists := unique_set[token]; !exists {
						stdout.WriteString(token)
						stdout.WriteByte('\n')
						total++
						unique_set[token] = true
					}
				}

				file.Close()

			}

			return
		}

		// multi file handling below
		sets := make([]map[string]bool, len(file_paths))

		// may require throttling due to disk thrashing
		// initial scan to fill the bloom filters
		for i, file_path := range file_paths {

			set := make(map[string]bool)

			file, err := os.Open(file_path)
			if err != nil {
				log.Fatal(err)
			}

			scanner := bufio.NewScanner(file)

			for scanner.Scan() {
				set[scanner.Text()] = true
			}

			file.Close()

			sets[i] = set

		}

		// do the work
		switch {

		// unique set of tokens that exist in all files
		case *intersection:

			echoed_set := make(map[string]bool)

			for _, file_path := range file_paths {

				file, err := os.Open(file_path)
				if err != nil {
					log.Fatal(err)
				}

				scanner := bufio.NewScanner(file)

			NEXT_TOKEN:
				for scanner.Scan() {

					token := scanner.Text()

					if _, echoed := echoed_set[token]; echoed {
						goto NEXT_TOKEN
					}

					for _, set := range sets {
						if _, in_this_set := set[token]; !in_this_set {
							goto NEXT_TOKEN
						}
					}

					stdout.WriteString(token)
					stdout.WriteByte('\n')
					total++
					echoed_set[token] = true

				}

				file.Close()

			}

		// unique set of tokens not in the intersection
		case *diff:

			echoed_set := make(map[string]bool)

			for _, file_path := range file_paths {

				file, err := os.Open(file_path)
				if err != nil {
					log.Fatal(err)
				}

				scanner := bufio.NewScanner(file)

				for scanner.Scan() {

					token := scanner.Text()

					if _, echoed := echoed_set[token]; echoed {
						continue
					}

					for _, set := range sets {
						if _, in_this_set := set[token]; !in_this_set {
							stdout.WriteString(token)
							stdout.WriteByte('\n')
							total++
							echoed_set[token] = true
							break
						}
					}

				}

				file.Close()

			}
		}

	}

}
<|endoftext|>


<commit_before>package main

import (
  "log"
  "os"
  "bytes"
  "fmt"
  "io"
  "mime/multipart"
  "net/http"
  "gopkg.in/fsnotify.v1"
  fp "path/filepath"
  "github.com/skratchdot/open-golang/open"
  "github.com/fatih/color"
  "gopkg.in/yaml.v2"
  "strings"
  "io/ioutil"
)

func post(path string, add, isFile bool, baseURL string) {

  var b bytes.Buffer
  w := multipart.NewWriter(&b)

  cwd, _ := os.Getwd()
  relPath, err := fp.Rel(cwd, path)
  if err != nil {
    log.Fatal(err)
    return
  }
  _ = w.WriteField("path", relPath)

  if (add && isFile) {
    // Add your image file
    f, err := os.Open(path)
    if err != nil {
        return
    }
    fw, err := w.CreateFormFile("file", path)
    if err != nil {
        return
    }
    if _, err = io.Copy(fw, f); err != nil {
        return
    }
  }

  w.Close()

  var url string
  switch {
    case !add:
      url = baseURL + "/remove"
    case add && isFile:
      url = baseURL + "/addFile"
    case add && !isFile:
      url = baseURL + "/addFolder"
  }

  req, err := http.NewRequest("POST", url, &b)
  if err != nil {
      return
  }
  // Don't forget to set the content type, this will contain the boundary.
  req.Header.Set("Content-Type", w.FormDataContentType())

  // Submit the request
  client := &http.Client{}
  _, err = client.Do(req)
  return

}

func handle(event fsnotify.Event, watcher *fsnotify.Watcher, baseURL string) {
  filepath := event.Name

  if strings.HasPrefix(fp.Base(filepath), ".") {
    return
  }

  // event type
  var add bool
  switch {
    case event.Op&fsnotify.Write == fsnotify.Write:
      add = true
    case event.Op&fsnotify.Create == fsnotify.Create:
      add = true
    case event.Op&fsnotify.Remove == fsnotify.Remove:
      add = false
    case event.Op&fsnotify.Rename == fsnotify.Rename:
      add = false
    default:
      return
  }

  if add {

    fi, err := os.Stat(filepath);
    switch {
      case err != nil:
        return
      case fi.IsDir():
        post(filepath, true, false, baseURL)
        err = watcher.Add(filepath)
        if err != nil {
          return
        }
      default:
        post(filepath, true, true, baseURL)
    }

  } else {
    post(filepath, false, false, baseURL)
  }
}

func checkDir() error {
  _, err := os.Stat("static")
  if err != nil {
    fmt.Printf("This command must be run inside your app directory\n")
    return err
  }
  return nil
}

func loadConfig() (string, string, string, error) {
  type CONFIG struct {
    NAME string
    URL string
    IP string
  }

  c := CONFIG{}

  data, err := ioutil.ReadFile(CONFIG_FILE)
  if err != nil {
    return "", "", "", err
  }
  err = yaml.Unmarshal(data, &c)
  if err != nil {
    return "", "", "", err
  }

  return c.NAME, c.URL, c.IP, nil
}

func up() {

  _, url, ip, err := loadConfig()
  if err != nil {
    fmt.Println(INDENT, color.RedString("This command must be run from inside your app's source directory"))
    return
  }

  previewURL := url
  baseURL := "http://" + ip + ":8888"

  open.Run(previewURL)
  fmt.Println(CHECKERED_FLAG, color.YellowString("Watching source files"))
  fmt.Println(INDENT, "Preview at", color.GreenString(url))

  err = checkDir()
  if err != nil {
    return
  }

  watcher, err := fsnotify.NewWatcher()
  if err != nil {
    log.Fatal(err)
  }
  defer watcher.Close()

  events := make(chan fsnotify.Event)
  go func() {
    for {
      event := <-events
      sem := make(chan int)
      go func() {
        handle(event, watcher, baseURL)
        sem <- 1
      }()
      <-sem
    }
  }()

  done := make(chan bool)
  go func() {
    for {
      select {
        case event := <-watcher.Events:
          events <- event
        case err := <-watcher.Errors:
          log.Println("error:", err)
      }
    }
  }()

  cwd, _ := os.Getwd()
  err = fp.Walk(cwd, func(path string, info os.FileInfo, _ error) error {
      if info.IsDir() {
        watcher.Add(path)
      }
      return nil
    })
  err = watcher.Add(cwd)
  if err != nil {
    log.Fatal(err)
  }
  <-done
}
<commit_msg>stdout change<commit_after>package main

import (
  "log"
  "os"
  "bytes"
  "fmt"
  "io"
  "mime/multipart"
  "net/http"
  "gopkg.in/fsnotify.v1"
  fp "path/filepath"
  "github.com/skratchdot/open-golang/open"
  "github.com/fatih/color"
  "gopkg.in/yaml.v2"
  "strings"
  "io/ioutil"
)

func post(path string, add, isFile bool, baseURL string) {

  var b bytes.Buffer
  w := multipart.NewWriter(&b)

  cwd, _ := os.Getwd()
  relPath, err := fp.Rel(cwd, path)
  if err != nil {
    log.Fatal(err)
    return
  }
  _ = w.WriteField("path", relPath)

  if (add && isFile) {
    // Add your image file
    f, err := os.Open(path)
    if err != nil {
        return
    }
    fw, err := w.CreateFormFile("file", path)
    if err != nil {
        return
    }
    if _, err = io.Copy(fw, f); err != nil {
        return
    }
  }

  w.Close()

  var url string
  switch {
    case !add:
      url = baseURL + "/remove"
    case add && isFile:
      url = baseURL + "/addFile"
    case add && !isFile:
      url = baseURL + "/addFolder"
  }

  req, err := http.NewRequest("POST", url, &b)
  if err != nil {
      return
  }
  // Don't forget to set the content type, this will contain the boundary.
  req.Header.Set("Content-Type", w.FormDataContentType())

  // Submit the request
  client := &http.Client{}
  _, err = client.Do(req)
  return

}

func handle(event fsnotify.Event, watcher *fsnotify.Watcher, baseURL string) {
  filepath := event.Name

  if strings.HasPrefix(fp.Base(filepath), ".") {
    return
  }

  // event type
  var add bool
  switch {
    case event.Op&fsnotify.Write == fsnotify.Write:
      add = true
    case event.Op&fsnotify.Create == fsnotify.Create:
      add = true
    case event.Op&fsnotify.Remove == fsnotify.Remove:
      add = false
    case event.Op&fsnotify.Rename == fsnotify.Rename:
      add = false
    default:
      return
  }

  if add {

    fi, err := os.Stat(filepath);
    switch {
      case err != nil:
        return
      case fi.IsDir():
        post(filepath, true, false, baseURL)
        err = watcher.Add(filepath)
        if err != nil {
          return
        }
      default:
        post(filepath, true, true, baseURL)
    }

  } else {
    post(filepath, false, false, baseURL)
  }
}

func checkDir() error {
  _, err := os.Stat("static")
  if err != nil {
    fmt.Printf("This command must be run inside your app directory\n")
    return err
  }
  return nil
}

func loadConfig() (string, string, string, error) {
  type CONFIG struct {
    NAME string
    URL string
    IP string
  }

  c := CONFIG{}

  data, err := ioutil.ReadFile(CONFIG_FILE)
  if err != nil {
    return "", "", "", err
  }
  err = yaml.Unmarshal(data, &c)
  if err != nil {
    return "", "", "", err
  }

  return c.NAME, c.URL, c.IP, nil
}

func up() {

  _, url, ip, err := loadConfig()
  if err != nil {
    fmt.Println(INDENT, color.RedString("This command must be run from inside your app's source directory"))
    return
  }

  previewURL := url
  baseURL := "http://" + ip + ":8888"

  open.Run(previewURL)
  fmt.Println(CHECKERED_FLAG, color.YellowString("Watching source files"))
  fmt.Println(ARROW, "Preview at", color.GreenString(url))
  fmt.Println(RED_CAR, color.YellowString("Now edit the source files in this folder and save to see live updates on the server."))

  err = checkDir()
  if err != nil {
    return
  }

  watcher, err := fsnotify.NewWatcher()
  if err != nil {
    log.Fatal(err)
  }
  defer watcher.Close()

  events := make(chan fsnotify.Event)
  go func() {
    for {
      event := <-events
      sem := make(chan int)
      go func() {
        handle(event, watcher, baseURL)
        sem <- 1
      }()
      <-sem
    }
  }()

  done := make(chan bool)
  go func() {
    for {
      select {
        case event := <-watcher.Events:
          events <- event
        case err := <-watcher.Errors:
          log.Println("error:", err)
      }
    }
  }()

  cwd, _ := os.Getwd()
  err = fp.Walk(cwd, func(path string, info os.FileInfo, _ error) error {
      if info.IsDir() {
        watcher.Add(path)
      }
      return nil
    })
  err = watcher.Add(cwd)
  if err != nil {
    log.Fatal(err)
  }
  <-done
}
<|endoftext|>


<commit_before>package ut

//
func Contains(s interface{}, o interface{}) bool {
	for _, obj := range s.([]interface{}) {
		if obj == o {
			return true
		}
	}
	return false
}

func Any(s interface{}, f func(interface{}) bool) bool {
	for _, obj := range s.([]interface{}) {
		if f(obj) {
			return true
		}
	}
	return false
}

func Pluck(s []map[string]interface{}, str string) []interface{} {
	var returned []interface{}

	for _, mp := range s {
		o := mp[str]
		if o != nil {
			returned = append(returned, o)
		}
	}

	return returned
}

func SlicesEqual(a interface{}, b interface{}) bool {
	if len(a.([]interface{})) != len(b.([]interface{})) {
		return false
	}
	for i, v := range a.([]interface{}) {
		if v != b.([]interface{})[i] {
			return false
		}
	}
	return true
}
<commit_msg>updating<commit_after>package ut

// Any takes a slice and a func. If the func ever returns true Any will
// return true
//
//      s := []int{1,2,3,4,5,6,7}
//      ut.Any(s, func(i interface{}) bool {
//          return i.(int) > 3
//      }) // true
//
func Any(s interface{}, f func(interface{}) bool) bool {
	for _, obj := range s.([]interface{}) {
		if f(obj) {
			return true
		}
	}
	return false
}

// Contains checks a slice to see if an object exists inside of it
//
//      s := []string{"hello","world"}
//      if ut.Contains(s, "hello") {
//  			print("yup it's there")
//      }
//
// Note the slice can be of any type
//
//     s := []interface{}{"hello","world", 1000}
//     if ut.Contains(s, 1000) {
//  	    print("yup it's there")
//     }
func Contains(s interface{}, o interface{}) bool {
	for _, obj := range s.([]interface{}) {
		if obj == o {
			return true
		}
	}
	return false
}

func Pluck(s []map[string]interface{}, str string) []interface{} {
	var returned []interface{}

	for _, mp := range s {
		o := mp[str]
		if o != nil {
			returned = append(returned, o)
		}
	}

	return returned
}

func SlicesEqual(a interface{}, b interface{}) bool {
	if len(a.([]interface{})) != len(b.([]interface{})) {
		return false
	}
	for i, v := range a.([]interface{}) {
		if v != b.([]interface{})[i] {
			return false
		}
	}
	return true
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	_ "net/http"
	_ "net/url"
	"os"
	"os/user"
	"path"
	"strings"
)

type Config struct {
	APIKey string
	City   string
}

type Cond struct {
	Clouds          int     `json:"cloudcover,string"`
	FeelsLikeC      int     `json:",string"`
	Humidity        float64 `json:"humidity,string"`
	ObservationTime string  `json:"Observation_time"`
	PrecipMM        float64 `json:"precipMM,string"`
	Pressure        int     `json:"pressure,string"`
	TempC           int     `json:"temp_C,string"`
	VisibleDistKM   int     `json:"visibility,string"`
	WeatherCode     int     `json:"weatherCode,string"`
	WeatherIconUrl  []struct{ Value string }
	Winddir16Point  string
	WinddirDegree   int `json:"winddirDegree,string"`
	WindspeedKmph   int `json:"windspeedKmph,string"`
	WindspeedMiles  int `json:"windspeedMiles,string"`
}

type Astro struct {
	Moonrise string
	Moonset  string
	Sunrise  string
	Sunset   string
}

type Weather struct {
	Astronomy []Astro
	Date      string
	Hourly    []Cond
	MaxtempC  int `json:"maxtempC,string"`
	MintempC  int `json:"mintempC,string"`
}

type Resp struct {
	Data struct {
		Cur     []Cond     `json:"current_condition"`
		Req     []struct{} `json:"request"`
		Weather []Weather  `json:"weather"`
	} `json:"data"`
}

type State struct {
	Desc      string
	DayIcon   []string
	NightIcon []string
}

var (
	config     Config
	configpath string
	params     []string
	codes      = map[int]State{
		0:   {"Unknown, please report", iconUnknown, iconUnknown},
		113: {"Klar", iconSunny, iconUnknown},
		116: {"Teilweise Wolkig", iconPartlyCloudy, iconUnknown},
	}

	iconUnknown = []string{
		"    .-.      ",
		"     __)     ",
		"    (        ",
		"     `-’     ",
		"      •      "}
	iconSunny = []string{
		"\033[38;5;226m    \\   /    \033[0m",
		"\033[38;5;226m     .-.     \033[0m",
		"\033[38;5;226m  ― (   ) ―  \033[0m",
		"\033[38;5;226m     `-’     \033[0m",
		"\033[38;5;226m    /   \\    \033[0m"}
	iconPartlyCloudy = []string{
		"\033[38;5;226m   \\  /\033[0m      ",
		"\033[38;5;226m _ /\"\"\033[0m.-.    ",
		"\033[38;5;226m   \\_\033[0m(   ).  ",
		"\033[38;5;226m   /\033[0m(___(__) ",
		"             "}
	iconLightShowers = []string{
		"\033[38;5;226m _`/\"\"\033[38;5;250m.-.    \033[0m",
		"\033[38;5;226m  ,\\_\033[38;5;250m(   ).  \033[0m",
		"\033[38;5;226m   /\033[38;5;250m(___(__) \033[0m",
		"\033[38;5;111m     ‘ ‘ ‘ ‘ \033[0m",
		"\033[38;5;111m    ‘ ‘ ‘ ‘  \033[0m"}
	iconHeavyShowers = []string{
		"\033[38;5;226m _`/\"\"\033[38;5;240;1m.-.    \033[0m",
		"\033[38;5;226m  ,\\_\033[38;5;240;1m(   ).  \033[0m",
		"\033[38;5;226m   /\033[38;5;240;1m(___(__) \033[0m",
		"\033[38;5;21;1m   ‚‘‚‘‚‘‚‘ \033[0m",
		"\033[38;5;21;1m   ‚’‚’‚’‚’ \033[0m"}
	iconLightSnow = []string{
		"\033[38;5;226m _`/\"\"\033[38;5;250m.-.    \033[0m",
		"\033[38;5;226m  ,\\_\033[38;5;250m(   ).  \033[0m",
		"\033[38;5;226m   /\033[38;5;250m(___(__) \033[0m",
		"\033[38;5;255m     *  *  * \033[0m",
		"\033[38;5;255m    *  *  *  \033[0m"}
	iconHeavySnow = []string{
		"\033[38;5;226m _`/\"\"\033[38;5;240;1m.-.    \033[0m",
		"\033[38;5;226m  ,\\_\033[38;5;240;1m(   ).  \033[0m",
		"\033[38;5;226m   /\033[38;5;240;1m(___(__) \033[0m",
		"\033[38;5;255;1m    * * * *  \033[0m",
		"\033[38;5;255;1m   * * * *   \033[0m"}
	iconThunderyShowers = []string{
		"\033[38;5;226m _`/\"\"\033[38;5;250m.-.    \033[0m",
		"\033[38;5;226m  ,\\_\033[38;5;250m(   ).  \033[0m",
		"\033[38;5;226m   /\033[38;5;250m(___(__) \033[0m",
		"    \033[38;5;228;5m⚡\033[38;5;111;25m‘ ‘\033[38;5;228;5m⚡\033[38;5;111;25m‘ ‘ \033[0m",
		"    \033[38;5;111m‘ ‘ ‘ ‘  \033[0m"}
	iconThunderySnow = []string{
		"\033[38;5;226m _`/\"\"\033[38;5;250m.-.    \033[0m",
		"\033[38;5;226m  ,\\_\033[38;5;250m(   ).  \033[0m",
		"\033[38;5;226m   /\033[38;5;250m(___(__) \033[0m",
		"\033[38;5;255m     *\033[38;5;228;5m⚡\033[38;5;255;25m *\033[38;5;228;5m⚡\033[38;5;255;25m * \033[0m",
		"\033[38;5;255m    *  *  *  \033[0m"}

//	cloud = "
//   .-.
//  (   ).
// (___(__)
//  ' ' '
// ' ' ' "
)

const (
	uri = "https://api.worldweatheronline.com/free/v2/weather.ashx?"
)

func configload() error {
	if b, err := ioutil.ReadFile(configpath); err == nil {
		return json.Unmarshal(b, &config)
	} else {
		return err
	}
}

func configsave() error {
	if j, err := json.MarshalIndent(config, "", "\t"); err == nil {
		return ioutil.WriteFile(configpath, j, 0600)
	} else {
		return err
	}
}

func init() {
	usr, err := user.Current()
	if err != nil {
		log.Fatal(err)
	}
	configpath = path.Join(usr.HomeDir, ".wegorc")
	config.APIKey = ""
	config.City = "New York"
	err = configload()
	if _, ok := err.(*os.PathError); ok {
		if err := configsave(); err != nil {
			log.Fatal(err)
		}
	} else if err != nil {
		log.Fatalf("could not parse %v: %v", configpath, err)
	}
}

func main() {
	for i := 1; i < len(os.Args); i++ {
		_ = os.Args[i]
	}

	//	if len(config.APIKey) > 0 {
	//		params = append(params, "key="+config.APIKey)
	//	}
	//	if len(config.City) > 0 {
	//		params = append(params, "q="+url.QueryEscape(config.City))
	//	}
	//	params = append(params, "format=json")
	//	params = append(params, "num_of_days=3")
	//	params = append(params, "tp=3")
	//	params = append(params, "lang=de")
	//
	//	res, err := http.Get(uri + strings.Join(params, "&"))
	//	defer res.Body.Close()
	//	if err != nil {
	//		log.Fatal(err)
	//	}
	//	body, err := ioutil.ReadAll(res.Body)
	//	if err != nil {
	//		log.Fatal(err)
	//	}
	//
	//	//	fmt.Println(string(body))
	//
	//	var r Resp
	//	if err = json.Unmarshal(body, &r); err != nil {
	//		log.Println(err)
	//	}
	//
	//	temp := r.Data.Cur[0].FeelsLikeC
	//	fmt.Println(temp)
	fmt.Println(strings.Join(iconSunny, "|\n"))
	fmt.Println(strings.Join(iconPartlyCloudy, "|\n"))
	fmt.Println(strings.Join(iconHeavyShowers, "|\n"))
	fmt.Println(strings.Join(iconThunderyShowers, "|\n"))
}
<commit_msg>basic output formatting<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"time"
	"log"
	"net/http"
	"net/url"
	"os"
	"os/user"
	"path"
	"strings"
)

type Config struct {
	APIKey string
	City   string
}

type Cond struct {
	ChanceOfRain   string  `json:"chanceofrain"`
	FeelsLikeC     int     `json:",string"`
	PrecipMM       float32 `json:"precipMM,string"`
	TempC          int     `json:"tempC,string"`
	Time           string  `json:"time"`
	VisibleDistKM  int     `json:"visibility,string"`
	WeatherCode    int     `json:"weatherCode,string"`
	WeatherDesc    []struct{ Value string }
	WindGustKmph   int    `json:",string"`
	Winddir16Point string
	WindspeedKmph  int    `json:"windspeedKmph,string"`
}

type Astro struct {
	Moonrise string
	Moonset  string
	Sunrise  string
	Sunset   string
}

type Weather struct {
	Astronomy []Astro
	Date      string
	Hourly    []Cond
	MaxtempC  int `json:"maxtempC,string"`
	MintempC  int `json:"mintempC,string"`
}

type Resp struct {
	Data struct {
		Cur     []Cond     `json:"current_condition"`
		Req     []struct{} `json:"request"`
		Weather []Weather  `json:"weather"`
	} `json:"data"`
}

type Icon struct {
	DayIcon   []string
	NightIcon []string
}

var (
	config     Config
	configpath string
	params     []string
	windDir    = map[string]string{
		"N":   "\033[1m↓\033[0m",
		"NNE": "\033[1m↓\033[0m",
		"NE":  "\033[1m↙\033[0m",
		"ENE": "\033[1m↙\033[0m",
		"E":   "\033[1m←\033[0m",
		"ESE": "\033[1m←\033[0m",
		"SE":  "\033[1m↖\033[0m",
		"SSE": "\033[1m↖\033[0m",
		"S":   "\033[1m↑\033[0m",
		"SSW": "\033[1m↑\033[0m",
		"SW":  "\033[1m↗\033[0m",
		"WSW": "\033[1m↗\033[0m",
		"W":   "\033[1m→\033[0m",
		"WNW": "\033[1m→\033[0m",
		"NW":  "\033[1m↘\033[0m",
		"NNW": "\033[1m↘\033[0m",
	}
	codes = map[int]Icon{
		0:   {iconUnknown, iconUnknown},
		113: {iconSunny, iconUnknown},
		116: {iconPartlyCloudy, iconUnknown},
		119: {iconUnknown, iconUnknown},
		122: {iconVeryCloudy, iconVeryCloudy},
		143: {iconUnknown, iconUnknown},
		176: {iconUnknown, iconUnknown},
		179: {iconUnknown, iconUnknown},
		182: {iconUnknown, iconUnknown},
		185: {iconUnknown, iconUnknown},
		200: {iconUnknown, iconUnknown},
		227: {iconUnknown, iconUnknown},
		230: {iconUnknown, iconUnknown},
		248: {iconUnknown, iconUnknown},
		260: {iconUnknown, iconUnknown},
		263: {iconUnknown, iconUnknown},
		266: {iconUnknown, iconUnknown},
		281: {iconUnknown, iconUnknown},
		284: {iconUnknown, iconUnknown},
		293: {iconUnknown, iconUnknown},
		296: {iconUnknown, iconUnknown},
		299: {iconUnknown, iconUnknown},
		302: {iconUnknown, iconUnknown},
		305: {iconUnknown, iconUnknown},
		308: {iconUnknown, iconUnknown},
		311: {iconUnknown, iconUnknown},
		314: {iconUnknown, iconUnknown},
		317: {iconUnknown, iconUnknown},
		320: {iconUnknown, iconUnknown},
		323: {iconUnknown, iconUnknown},
		326: {iconUnknown, iconUnknown},
		329: {iconUnknown, iconUnknown},
		332: {iconUnknown, iconUnknown},
		335: {iconUnknown, iconUnknown},
		338: {iconUnknown, iconUnknown},
		350: {iconUnknown, iconUnknown},
		353: {iconUnknown, iconUnknown},
		356: {iconUnknown, iconUnknown},
		359: {iconUnknown, iconUnknown},
		362: {iconUnknown, iconUnknown},
		365: {iconUnknown, iconUnknown},
		368: {iconUnknown, iconUnknown},
		371: {iconUnknown, iconUnknown},
		374: {iconUnknown, iconUnknown},
		377: {iconUnknown, iconUnknown},
		386: {iconUnknown, iconUnknown},
		389: {iconUnknown, iconUnknown},
		392: {iconUnknown, iconUnknown},
		395: {iconUnknown, iconUnknown},
	}

	iconUnknown = []string{
		"    .-.      ",
		"     __)     ",
		"    (        ",
		"     `-’     ",
		"      •      "}
	iconSunny = []string{
		"\033[38;5;226m    \\   /    \033[0m",
		"\033[38;5;226m     .-.     \033[0m",
		"\033[38;5;226m  ― (   ) ―  \033[0m",
		"\033[38;5;226m     `-’     \033[0m",
		"\033[38;5;226m    /   \\    \033[0m"}
	iconPartlyCloudy = []string{
		"\033[38;5;226m   \\  /\033[0m      ",
		"\033[38;5;226m _ /\"\"\033[0m.-.    ",
		"\033[38;5;226m   \\_\033[0m(   ).  ",
		"\033[38;5;226m   /\033[0m(___(__) ",
		"             "}
	iconVeryCloudy = []string{
		"             ",
		"\033[38;5;240m     .--.    \033[0m",
		"\033[38;5;240m  .-(    ).  \033[0m",
		"\033[38;5;240m (___.__)__) \033[0m",
		"             "}
	iconLightShowers = []string{
		"\033[38;5;226m _`/\"\"\033[38;5;250m.-.    \033[0m",
		"\033[38;5;226m  ,\\_\033[38;5;250m(   ).  \033[0m",
		"\033[38;5;226m   /\033[38;5;250m(___(__) \033[0m",
		"\033[38;5;111m     ‘ ‘ ‘ ‘ \033[0m",
		"\033[38;5;111m    ‘ ‘ ‘ ‘  \033[0m"}
	iconHeavyShowers = []string{
		"\033[38;5;226m _`/\"\"\033[38;5;240;1m.-.    \033[0m",
		"\033[38;5;226m  ,\\_\033[38;5;240;1m(   ).  \033[0m",
		"\033[38;5;226m   /\033[38;5;240;1m(___(__) \033[0m",
		"\033[38;5;21;1m   ‚‘‚‘‚‘‚‘ \033[0m",
		"\033[38;5;21;1m   ‚’‚’‚’‚’ \033[0m"}
	iconLightSnow = []string{
		"\033[38;5;226m _`/\"\"\033[38;5;250m.-.    \033[0m",
		"\033[38;5;226m  ,\\_\033[38;5;250m(   ).  \033[0m",
		"\033[38;5;226m   /\033[38;5;250m(___(__) \033[0m",
		"\033[38;5;255m     *  *  * \033[0m",
		"\033[38;5;255m    *  *  *  \033[0m"}
	iconHeavySnow = []string{
		"\033[38;5;226m _`/\"\"\033[38;5;240;1m.-.    \033[0m",
		"\033[38;5;226m  ,\\_\033[38;5;240;1m(   ).  \033[0m",
		"\033[38;5;226m   /\033[38;5;240;1m(___(__) \033[0m",
		"\033[38;5;255;1m    * * * *  \033[0m",
		"\033[38;5;255;1m   * * * *   \033[0m"}
	iconThunderyShowers = []string{
		"\033[38;5;226m _`/\"\"\033[38;5;250m.-.    \033[0m",
		"\033[38;5;226m  ,\\_\033[38;5;250m(   ).  \033[0m",
		"\033[38;5;226m   /\033[38;5;250m(___(__) \033[0m",
		"    \033[38;5;228;5m⚡\033[38;5;111;25m‘ ‘\033[38;5;228;5m⚡\033[38;5;111;25m‘ ‘ \033[0m",
		"    \033[38;5;111m‘ ‘ ‘ ‘  \033[0m"}
	iconThunderySnow = []string{
		"\033[38;5;226m _`/\"\"\033[38;5;250m.-.    \033[0m",
		"\033[38;5;226m  ,\\_\033[38;5;250m(   ).  \033[0m",
		"\033[38;5;226m   /\033[38;5;250m(___(__) \033[0m",
		"\033[38;5;255m     *\033[38;5;228;5m⚡\033[38;5;255;25m *\033[38;5;228;5m⚡\033[38;5;255;25m * \033[0m",
		"\033[38;5;255m    *  *  *  \033[0m"}

//	cloud = "
//   .-.
//  (   ).
// (___(__)
//  ' ' '
// ' ' ' "
)

const (
	uri = "https://api.worldweatheronline.com/free/v2/weather.ashx?"
)

func configload() error {
	if b, err := ioutil.ReadFile(configpath); err == nil {
		return json.Unmarshal(b, &config)
	} else {
		return err
	}
}

func configsave() error {
	if j, err := json.MarshalIndent(config, "", "\t"); err == nil {
		return ioutil.WriteFile(configpath, j, 0600)
	} else {
		return err
	}
}

func formatTemp(c Cond) string {
	return fmt.Sprintf("%d – %d °C", c.FeelsLikeC, c.TempC)
}

func formatWind(c Cond) string {
	if c.WindGustKmph > c.WindspeedKmph {
		return fmt.Sprintf("%s %d – %d km/h", windDir[c.Winddir16Point], c.WindspeedKmph, c.WindGustKmph)
	} else {
		return fmt.Sprintf("%s %d km/h", windDir[c.Winddir16Point], c.WindspeedKmph)
	}
}

func formatVisibility(c Cond) string {
	return fmt.Sprintf("%d km", c.VisibleDistKM)
}

func formatRain(c Cond) string {
	if c.ChanceOfRain != "" {
		return fmt.Sprintf("%v mm | %s%%", c.PrecipMM, c.ChanceOfRain)
	} else {
		return fmt.Sprintf("%v mm", c.PrecipMM)
	}
}

func formatCond(cur []string, c Cond) (ret []string) {
	var icon Icon
	if i, ok := codes[c.WeatherCode]; !ok {
		i.DayIcon = iconUnknown
		i.NightIcon = iconUnknown
		icon = i
	} else {
		icon = i
	}
	ret = append(ret, fmt.Sprintf("%v %v %-15v", cur[0], icon.DayIcon[0], c.WeatherDesc[0].Value))
	ret = append(ret, fmt.Sprintf("%v %v %-15v", cur[1], icon.DayIcon[1], formatTemp(c)))
	ret = append(ret, fmt.Sprintf("%v %v %-23v", cur[2], icon.DayIcon[2], formatWind(c)))
	ret = append(ret, fmt.Sprintf("%v %v %-15v", cur[3], icon.DayIcon[3], formatVisibility(c)))
	ret = append(ret, fmt.Sprintf("%v %v %-15v", cur[4], icon.DayIcon[4], formatRain(c)))
	return
}

func printDay(w Weather) (ret []string) {
	hourly := w.Hourly
	ret = make([]string, 5)
	for i := range ret {
		ret[i] = "│"
	}
	for _, h := range hourly {
		if h.Time == "100" || h.Time == "400" || h.Time == "700" || h.Time == "1600" {
			continue
		}
		ret = formatCond(ret, h)
		for i := range ret {
			ret[i] = ret[i] + "│"
		}
	}
	d, _ := time.Parse("2006-01-02", w.Date)
	dateFmt := "┤ " + d.Format("Mon 02. Jan") + " ├"
	ret = append([]string{
		"                                                       ┌─────────────┐                                                       ",
		"┌──────────────────────────────┬───────────────────────" + dateFmt + "───────────────────────┬──────────────────────────────┐",
		"│           Morning            │             Noon      └──────┬──────┘    Evening            │            Night             │",
		"├──────────────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────┤"},
		ret...)
	return append(ret,
		"└──────────────────────────────┴──────────────────────────────┴──────────────────────────────┴──────────────────────────────┘")
	return
}

func init() {
	usr, err := user.Current()
	if err != nil {
		log.Fatal(err)
	}
	configpath = path.Join(usr.HomeDir, ".wegorc")
	config.APIKey = ""
	config.City = "New York"
	err = configload()
	if _, ok := err.(*os.PathError); ok {
		if err := configsave(); err != nil {
			log.Fatal(err)
		}
	} else if err != nil {
		log.Fatalf("could not parse %v: %v", configpath, err)
	}
}

func main() {
	for i := 1; i < len(os.Args); i++ {
		_ = os.Args[i]
	}

	if len(config.APIKey) > 0 {
		params = append(params, "key="+config.APIKey)
	}
	if len(config.City) > 0 {
		params = append(params, "q="+url.QueryEscape(config.City))
	}
	params = append(params, "format=json")
	params = append(params, "num_of_days=3")
	params = append(params, "tp=3")
	params = append(params, "lang=de")

	res, err := http.Get(uri + strings.Join(params, "&"))
	defer res.Body.Close()
	if err != nil {
		log.Fatal(err)
	}
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		log.Fatal(err)
	}

//	fmt.Println(string(body))

	var r Resp
	if err = json.Unmarshal(body, &r); err != nil {
		log.Println(err)
	}

	out := formatCond(make([]string, 5), r.Data.Cur[0])
	for _, val := range out {
		fmt.Println(val)
	}

	for _, d := range r.Data.Weather {
		for _, val := range printDay(d) {
			fmt.Println(val)
		}
	}
	//	fmt.Println(strings.Join(iconSunny, "|\n"))
	//	fmt.Println(strings.Join(iconPartlyCloudy, "|\n"))
	//	fmt.Println(strings.Join(iconHeavyShowers, "|\n"))
	//	fmt.Println(strings.Join(iconThunderyShowers, "|\n"))
}
<|endoftext|>


<commit_before>package ucloud
<commit_msg>add udb<commit_after>package ucloud

// ---------------- BackupUdbInstance ------------------

type BackupUdbInstanceResponse struct {
	BaseResponse
}

func (r *BackupUdbInstanceResponse) Data() interface{} {
	return r.RetCode
}

type BackupUdbInstance struct {
	Region       string // 数据中心，请参见数据中心RegionList
	DBId         string // DB实例Id
	BackupName   string // 备份名称
	UseBlacklist bool   `ucloud:"optional"` // 是否使用黑名单备份，默认false

}

func (r *BackupUdbInstance) R() UResponse {
	return &BackupUdbInstanceResponse{}
}

// ---------------- ClearUdbLog ------------------

type ClearUdbLogResponse struct {
	BaseResponse
}

func (r *ClearUdbLogResponse) Data() interface{} {
	return r.RetCode
}

type ClearUdbLog struct {
	Region     string // 数据中心，请参见数据中心RegionList
	DBId       string // DB实例的id
	LogType    int    // 日志类型，10-error（暂不支持）、20-slow（暂不支持）、30-binlog
	BeforeTime int    `ucloud:"optional"` // 删除时间点(至少前一天)之前log，采用时间戳(秒)，默认当前时间点前一天

}

func (r *ClearUdbLog) R() UResponse {
	return &ClearUdbLogResponse{}
}

// ---------------- CreateUdbInstance ------------------

type CreateUdbInstanceResponse struct {
	BaseResponse
	DBId string `json:"omitempty"` // db实例id

}

func (r *CreateUdbInstanceResponse) Data() interface{} {
	return r.DBId
}

type CreateUdbInstance struct {
	Region         string // 数据中心，请参见数据中心RegionList
	DBTypeId       string // DB类型id，mysql/mongodb按版本细分各有一个id1：mysql-5.5，2：mysql-5.1，3：percona-5.54：mongodb-2.4，5：mongodb-2.6，6：mysql-5.6，7：percona-5.6
	ChargeType     string `ucloud:"optional"` // Year， Month， Dynamic，Trial，默认: Dynamic
	CouponId       string `ucloud:"optional"` // 使用的代金券id
	Quantity       int    `ucloud:"optional"` // 购买时长，默认值1
	Name           string // 实例名称，至少6位
	AdminUser      string `ucloud:"optional"` // 管理员帐户名，默认root
	AdminPassword  string // 管理员密码
	Port           int    `ucloud:"optional"` // 端口号，mysql默认3306，mongodb默认27017
	ParamGroupId   int    // DB实例使用的配置参数组id
	MemoryLimit    int    // 内存限制(MB)，目前支持以下几档600M/1500M/3000M/6000M/15000M/30000M
	DiskSpace      int    // 磁盘空间(GB), 暂时支持20G - 500G
	BackupCount    int    `ucloud:"optional"` // 备份策略，每周备份数量，默认7次
	BackupTime     int    `ucloud:"optional"` // 备份策略，备份开始时间，单位小时计，默认3点
	BackupDuration int    `ucloud:"optional"` // 备份策略，备份时间间隔，单位小时计，默认24小时
	BackupId       int    `ucloud:"optional"` // 备份id，如果指定，则表明从备份恢复实例
	UseSSD         bool   `ucloud:"optional"` // 是否使用SSD，默认为false

}

func (r *CreateUdbInstance) R() UResponse {
	return &CreateUdbInstanceResponse{}
}

// ---------------- CreateUdbParamGroup ------------------

type CreateUdbParamGroupResponse struct {
	BaseResponse
	GroupId int `json:"omitempty"` // 新配置参数组id

}

func (r *CreateUdbParamGroupResponse) Data() interface{} {
	return r.GroupId
}

type CreateUdbParamGroup struct {
	Region      string // 数据中心，请参见数据中心RegionList
	GroupName   string // 新配置参数组名称
	Description string // 参数组描述
	SrcGroupId  int    // 源参数组id
	DBTypeId    string // DB类型id，mysql/mongodb按版本细分各有一个id1：mysql-5.5，2：mysql-5.1，3：percona-5.54：mongodb-2.4，5：mongodb-2.6，6：mysql-5.6，7：percona-5.6

}

func (r *CreateUdbParamGroup) R() UResponse {
	return &CreateUdbParamGroupResponse{}
}

// ---------------- CreateUdbReplicationInstance ------------------

type CreateUdbReplicationInstanceResponse struct {
	BaseResponse
	DBId string `json:"omitempty"` // 创建从节点的DBId

}

func (r *CreateUdbReplicationInstanceResponse) Data() interface{} {
	return r.DBId
}

type CreateUdbReplicationInstance struct {
	Region    string // 数据中心，请参见数据中心RegionList
	SrcId     string // primary节点的DBId
	Name      string // 实例名称，至少6位
	Port      int    `ucloud:"optional"` // 端口号，默认27017
	IsArbiter bool   `ucloud:"optional"` // 是否是仲裁节点，默认false，仲裁节点按最小机型创建
	CouponId  string `ucloud:"optional"` // 使用的代金券id

}

func (r *CreateUdbReplicationInstance) R() UResponse {
	return &CreateUdbReplicationInstanceResponse{}
}

// ---------------- CreateUdbSlave ------------------

type CreateUdbSlaveResponse struct {
	BaseResponse
	DBId string `json:"omitempty"` // 创建slave的DBId

}

func (r *CreateUdbSlaveResponse) Data() interface{} {
	return r.DBId
}

type CreateUdbSlave struct {
	Region   string // 数据中心，请参见数据中心RegionList
	SrcId    string // master实例的DBId
	Name     string // 实例名称，至少6位
	Port     int    `ucloud:"optional"` // 端口号，mysql默认3306
	UseSSD   bool   `ucloud:"optional"` // 是否使用SSD，默认为false
	CouponId string `ucloud:"optional"` // 使用的代金券id
	IsLock   bool   `ucloud:"optional"` // 是否锁主库，默认为true

}

func (r *CreateUdbSlave) R() UResponse {
	return &CreateUdbSlaveResponse{}
}

// ---------------- DeleteUdbBackup ------------------

type DeleteUdbBackupResponse struct {
	BaseResponse
}

func (r *DeleteUdbBackupResponse) Data() interface{} {
	return r.RetCode
}

type DeleteUdbBackup struct {
	Region   string // 数据中心，请参见数据中心RegionList
	BackupId int    // 备份id，可通过DescribeUDBBackup获得

}

func (r *DeleteUdbBackup) R() UResponse {
	return &DeleteUdbBackupResponse{}
}

// ---------------- DeleteUdbInstance ------------------

type DeleteUdbInstanceResponse struct {
	BaseResponse
}

func (r *DeleteUdbInstanceResponse) Data() interface{} {
	return r.RetCode
}

type DeleteUdbInstance struct {
	Region string // 数据中心，请参见数据中心RegionList
	DBId   string // DB实例的id

}

func (r *DeleteUdbInstance) R() UResponse {
	return &DeleteUdbInstanceResponse{}
}

// ---------------- DeleteUdbParamGroup ------------------

type DeleteUdbParamGroupResponse struct {
	BaseResponse
}

func (r *DeleteUdbParamGroupResponse) Data() interface{} {
	return r.RetCode
}

type DeleteUdbParamGroup struct {
	Region  string // 数据中心，请参见数据中心RegionList
	GroupId int    // 参数组id

}

func (r *DeleteUdbParamGroup) R() UResponse {
	return &DeleteUdbParamGroupResponse{}
}

// ---------------- DescribeUdbBackupBlacklist ------------------

type DescribeUdbBackupBlacklistResponse struct {
	BaseResponse
	Blacklist string `json:"omitempty"` // 黑名单

}

func (r *DescribeUdbBackupBlacklistResponse) Data() interface{} {
	return r.Blacklist
}

type DescribeUdbBackupBlacklist struct {
	Region string // 数据中心，请参见数据中心RegionList
	DBId   string // DB实例Id

}

func (r *DescribeUdbBackupBlacklist) R() UResponse {
	return &DescribeUdbBackupBlacklistResponse{}
}

// ---------------- DescribeUdbBackup ------------------
type DescribeUdbBackupDataSet struct {
	BackupId   int    // 备份id
	BackupName string // 备份名称
	BackupTime int    // 备份时间
	BackupSize int    // 备份文件大小
	BackupType int    // 备份类型，包括0-自动，1-手动
	State      string // 备份状态Backuping          // 备份中Success            // 备份成功Failed             // 备份失败Expired            // 备份过期
	DBId       string // dbid
	DBName     string // 对应的db名称
}

type DescribeUdbBackupResponse struct {
	BaseResponse
	DataSet    []*DescribeUdbBackupDataSet `json:"omitempty"` // 备份信息
	TotalCount int                         `json:"omitempty"` // 备份总数，如果指定dbid，则是该db备份总数

}

func (r *DescribeUdbBackupResponse) Data() interface{} {
	return r.DataSet
}

type DescribeUdbBackup struct {
	Region     string // 数据中心，请参见数据中心RegionList
	Offset     int    // 分页显示的起始偏移，列表操作则指定
	Limit      int    // 分页显示的条目数，列表操作则指定
	DBId       string `ucloud:"optional"` // DB实例Id，如果指定，则只获取该db的备份信息
	BackupType int    `ucloud:"optional"` // 备份类型，包括0-自动，1-手动
	BeginTime  int    `ucloud:"optional"` // 过滤条件:起始时间(时间戳)
	EndTime    int    `ucloud:"optional"` // 过滤条件:结束时间(时间戳)

}

func (r *DescribeUdbBackup) R() UResponse {
	return &DescribeUdbBackupResponse{}
}

// ---------------- DescribeUdbInstancePrice ------------------
type DescribeUdbInstancePriceDataSet struct {
	ChargeType string  // Year， Month， Dynamic，Trial
	Price      float64 // 价格，单位分
}

type DescribeUdbInstancePriceResponse struct {
	BaseResponse
	DataSet []*DescribeUdbInstancePriceDataSet `json:"omitempty"` // 价格

}

func (r *DescribeUdbInstancePriceResponse) Data() interface{} {
	return r.DataSet
}

type DescribeUdbInstancePrice struct {
	Region      string // 数据中心，请参见数据中心RegionList
	Count       int    // 购买DB实例数量
	ChargeType  string `ucloud:"optional"` // Year， Month， Dynamic，Trial，默认: Dynamic如果不指定，则一次性获取三种计费
	Quantity    int    `ucloud:"optional"` // 购买DB的时长，默认值为1
	MemoryLimit int    // 内存限制(MB)，目前支持以下几档600M/1500M/3000M/6000M/15000M/30000M
	DiskSpace   int    // 磁盘空间(GB), 暂时支持20G - 500G
	UseSSD      bool   `ucloud:"optional"` // 是否使用SSD，默认为false

}

func (r *DescribeUdbInstancePrice) R() UResponse {
	return &DescribeUdbInstancePriceResponse{}
}

// ---------------- DescribeUdbInstance ------------------
type DescribeUdbInstanceDataSet struct {
	DBId            string                        // DB实例id
	Name            string                        // 实例名称，至少6位
	DBTypeId        string                        // DB类型id，mysql/mongodb按版本细分各有一个id1：mysql-5.5，2：mysql-5.1，3：percona-5.54：mongodb-2.4，5：mongodb-2.6，6：mysql-5.6，7：percona-5.6
	ParamGroupId    int                           // DB实例使用的配置参数组id
	AdminUser       string                        // 管理员帐户名，默认root
	VirtualIP       string                        // DB实例虚ip
	VirtualIPMac    string                        // DB实例虚ip的mac地址
	Port            int                           // 端口号，mysql默认3306，mongodb默认27017
	SrcDBId         string                        // 对mysql的slave而言是master的DBId，对master则为空，对mongodb则是副本集id
	BackupCount     int                           // 备份策略，每周备份数量，默认7次
	BackupBeginTime int                           // 备份策略，备份开始时间，单位小时计，默认3点
	BackupDuration  int                           // 备份策略，备份时间间隔，单位小时计，默认24小时
	BackupBlacklist string                        // 备份策略，备份黑名单，mongodb则不适用
	State           string                        // DB状态标记Init                           // 初始化中Fail                           // 安装失败Starting                       // 启动中Running                        // 运行Shutdown                       // 关闭中Shutoff                        // 已关闭Delete                         // 已删除Upgrading                      // 升级中Promoting                      // 提升为独库进行中Recovering                     // 恢复中Recover fail                   // 恢复失败
	CreateTime      int                           // DB实例创建时间，采用UTC计时时间戳
	ModifyTime      int                           // DB实例修改时间，采用UTC计时时间戳
	ExpiredTime     int                           // DB实例过期时间，采用UTC计时时间戳
	ChargeType      string                        // Year， Month， Dynamic，Trial，默认: Dynamic
	MemoryLimit     int                           // 内存限制(MB)，默认根据配置机型
	DiskSpace       int                           // 磁盘空间(GB), 默认根据配置机型
	UseSSD          bool                          // 是否使用SSD
	Role            string                        // DB实例角色，mysql区分master/slave，mongodb多种角色
	DiskUsedSize    int                           // DB实例磁盘已使用空间，单位GB
	DataFileSize    int                           // DB实例数据文件大小，单位GB
	SystemFileSize  int                           // DB实例系统文件大小，单位GB
	LogFileSize     int                           // DB实例日志文件大小，单位GB
	DataSet         []*DescribeUdbInstanceDataSet // 如果列表操作，则有从DB实例信息列表
}

type DescribeUdbInstanceResponse struct {
	BaseResponse
	DataSet    []*DescribeUdbInstanceDataSet `json:"omitempty"` // DB实例信息列表
	TotalCount int                           `json:"omitempty"` // 用户db组的数量，对于mysql: 主从结对数量，没有slave，则只有master mongodb: 副本集数量

}

func (r *DescribeUdbInstanceResponse) Data() interface{} {
	return r.DataSet
}

type DescribeUdbInstance struct {
	Region    string // 数据中心，请参见数据中心RegionList
	DBId      string `ucloud:"optional"` // DB实例id，如果指定则获取描述，否则为列表操作，指定Offset/Limit
	ClassType string `ucloud:"optional"` // DB种类，分为SQL和NOSQL，如果是别表操作，则需要制定
	Offset    int    `ucloud:"optional"` // 分页显示起始偏移位置，列表操作则指定
	Limit     int    `ucloud:"optional"` // 分页显示数量，列表操作则指定

}

func (r *DescribeUdbInstance) R() UResponse {
	return &DescribeUdbInstanceResponse{}
}

// ---------------- DescribeUdbInstanceState ------------------

type DescribeUdbInstanceStateResponse struct {
	BaseResponse
	State string `json:"omitempty"` // DB状态标记 Init          // 初始化中 Fail              // 安装失败 Starting          // 启动中 Running           // 运行 Shutdown          // 关闭中 Shutoff           // 已关闭 Delete            // 已删除 Upgrading         // 升级中 Promoting         // 提升为独库进行中 Recovering        // 恢复中 Recover    fail   // 恢复失败
}

func (r *DescribeUdbInstanceStateResponse) Data() interface{} {
	return r.State
}

type DescribeUdbInstanceState struct {
	Region string // 数据中心，请参见数据中心RegionList
	DBId   string // 实例的Id

}

func (r *DescribeUdbInstanceState) R() UResponse {
	return &DescribeUdbInstanceStateResponse{}
}

// ---------------- DescribeUdbParamGroup ------------------
type DescribeUdbParamGroupDataSet struct {
	GroupId     int            // 参数组id
	GroupName   string         // 参数组名称
	DBTypeId    string         // DB类型id，mysql/mongodb按版本细分各有一个id1：mysql-5.5，2：mysql-5.1，3：percona-5.54：mongodb-2.4，5：mongodb-2.6，6：mysql-5.67：percona-5.6
	Description string         // 参数组描述
	Modifiable  bool           // 参数组是否可修改，默认值为true
	ParamMember []*ParamMember `json:",omitempty"` // 参数的键值对
}
type ParamMember struct {
	Key        string // 参数名称
	Value      string // 参数值
	ValueType  int    // 参数值应用类型，包括0-unknown、10-int、20-string、30-bool
	AllowedVal string // 允许的值(根据参数类型，用分隔符表示)
	ApplyType  int    // 参数值应用类型，包括0-unknown、10-static、20-dynamic
	Modifiable bool   // 是否可更改，默认为false
	FormatType int    // 允许值得格式类型，包括PVFT_UNKOWN=0,PVFT_RANGE=10, PVFT_ENUM=20
}

type DescribeUdbParamGroupResponse struct {
	BaseResponse
	DataSet    []*DescribeUdbParamGroupDataSet `json:"omitempty"` // 参数组
	TotalCount int                             `json:"omitempty"` // 参数组总数，列表操作时才会有该参数

}

func (r *DescribeUdbParamGroupResponse) Data() interface{} {
	return r.DataSet
}

type DescribeUdbParamGroup struct {
	Region  string // 数据中心，请参见数据中心RegionList
	GroupId int    `ucloud:"optional"` // 参数组id，如果指定则获取描述，否则是列表操作，需要指定Offset/Limit
	Offset  int    `ucloud:"optional"` // 分页显示的起始偏移，列表操作则指定
	Limit   int    `ucloud:"optional"` // 分页显示的条目数，列表操作则指定

}

func (r *DescribeUdbParamGroup) R() UResponse {
	return &DescribeUdbParamGroupResponse{}
}

// ---------------- DescribeUdbType ------------------
type DescribeUdbTypeDataSet struct {
	DBTypeId string // DB类型id，mysql/mongodb按版本细分各有一个id1：mysql-5.5，2：mysql-5.1，3：percona-5.54：mongodb-2.4，5：mongodb-2.6，6：mysql-5.6，7：percona-5.6
}

type DescribeUdbTypeResponse struct {
	BaseResponse
	DataSet []*DescribeUdbTypeDataSet `json:"omitempty"` // DB类型列表

}

func (r *DescribeUdbTypeResponse) Data() interface{} {
	return r.DataSet
}

type DescribeUdbType struct {
	Region string // 数据中心，请参见数据中心RegionList

}

func (r *DescribeUdbType) R() UResponse {
	return &DescribeUdbTypeResponse{}
}

// ---------------- EditUdbBackupBlacklist ------------------

type EditUdbBackupBlacklistResponse struct {
	BaseResponse
}

func (r *EditUdbBackupBlacklistResponse) Data() interface{} {
	return r.RetCode
}

type EditUdbBackupBlacklist struct {
	Region    string // 数据中心，请参见数据中心RegionList
	DBId      string // DB实例Id
	Blacklist string // 黑名单，规范示例abc.%;user.%;city.address;

}

func (r *EditUdbBackupBlacklist) R() UResponse {
	return &EditUdbBackupBlacklistResponse{}
}

// ---------------- ModifyUdbInstanceName ------------------

type ModifyUdbInstanceNameResponse struct {
	BaseResponse
}

func (r *ModifyUdbInstanceNameResponse) Data() interface{} {
	return r.RetCode
}

type ModifyUdbInstanceName struct {
	Region string // 数据中心，请参见数据中心RegionList
	DBId   string // 实例的Id
	Name   string // 实例的新名字

}

func (r *ModifyUdbInstanceName) R() UResponse {
	return &ModifyUdbInstanceNameResponse{}
}

// ---------------- PromoteUdbSlave ------------------

type PromoteUdbSlaveResponse struct {
	BaseResponse
}

func (r *PromoteUdbSlaveResponse) Data() interface{} {
	return r.RetCode
}

type PromoteUdbSlave struct {
	Region  string // 数据中心，请参见数据中心RegionList
	DBId    string // 实例的Id
	IsForce bool   `ucloud:"optional"` // 是否强制(如果从库落后可能会禁止提升)，默认false如果落后情况下，强制提升丢失数据

}

func (r *PromoteUdbSlave) R() UResponse {
	return &PromoteUdbSlaveResponse{}
}

// ---------------- RestartUdbInstance ------------------

type RestartUdbInstanceResponse struct {
	BaseResponse
}

func (r *RestartUdbInstanceResponse) Data() interface{} {
	return r.RetCode
}

type RestartUdbInstance struct {
	Region string // 数据中心，请参见数据中心RegionList
	DBId   string // 实例的Id

}

func (r *RestartUdbInstance) R() UResponse {
	return &RestartUdbInstanceResponse{}
}

// ---------------- StartUdbInstance ------------------

type StartUdbInstanceResponse struct {
	BaseResponse
}

func (r *StartUdbInstanceResponse) Data() interface{} {
	return r.RetCode
}

type StartUdbInstance struct {
	Region string // 数据中心，请参见数据中心RegionList
	DBId   string // 实例的Id

}

func (r *StartUdbInstance) R() UResponse {
	return &StartUdbInstanceResponse{}
}

// ---------------- StopUdbInstance ------------------

type StopUdbInstanceResponse struct {
	BaseResponse
}

func (r *StopUdbInstanceResponse) Data() interface{} {
	return r.RetCode
}

type StopUdbInstance struct {
	Region string // 数据中心，请参见数据中心RegionList
	DBId   string // 实例的Id

}

func (r *StopUdbInstance) R() UResponse {
	return &StopUdbInstanceResponse{}
}

// ---------------- UpdateUdbParamGroup ------------------

type UpdateUdbParamGroupResponse struct {
	BaseResponse
}

func (r *UpdateUdbParamGroupResponse) Data() interface{} {
	return r.RetCode
}

type UpdateUdbParamGroup struct {
	Region  string // 数据中心，请参见数据中心RegionList
	GroupId int    // 配置参数组id，使用DescribeUDBParamGroup获得
	Key     string // 参数名称
	Value   string // 参数值

}

func (r *UpdateUdbParamGroup) R() UResponse {
	return &UpdateUdbParamGroupResponse{}
}

// ---------------- UploadUdbParamGroup ------------------

type UploadUdbParamGroupResponse struct {
	BaseResponse
	GroupId int `json:"omitempty"` // 配置参数组id

}

func (r *UploadUdbParamGroupResponse) Data() interface{} {
	return r.GroupId
}

type UploadUdbParamGroup struct {
	Region      string // 数据中心，请参见数据中心RegionList
	DBTypeId    string // DB类型id，mysql/mongodb按版本细分各有一个id1：mysql-5.5，2：mysql-5.1，3：percona-5.54：mongodb-2.4，5：mongodb-2.6，6：mysql-5.6，7：percona-5.6
	GroupName   string // 配置参数组名称
	Description string // 参数组描述
	Content     string // 配置内容，导入的配置内容采用base64编码。mysql只支持[mysqld]段，如：[mysqld]back_log=102character_set_server=utf8......mongodb则不需要带段，如：auth=truemaxConns=2000......

}

func (r *UploadUdbParamGroup) R() UResponse {
	return &UploadUdbParamGroupResponse{}
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"os"
	"os/exec"
	"strings"

	"github.com/sirupsen/logrus"

	"k8s.io/test-infra/experiment/autobumper/bumper"
	"k8s.io/test-infra/prow/config/secret"
	"k8s.io/test-infra/prow/github"
)

const (
	oncallAddress = "https://storage.googleapis.com/kubernetes-jenkins/oncall.json"
	githubOrg     = "kubernetes"
	githubRepo    = "test-infra"
)

var extraFiles = map[string]bool{
	"releng/generate_tests.py":       true,
	"images/kubekins-e2e/Dockerfile": true,
}

func cdToRootDir() error {
	if bazelWorkspace := os.Getenv("BUILD_WORKSPACE_DIRECTORY"); bazelWorkspace != "" {
		if err := os.Chdir(bazelWorkspace); err != nil {
			return fmt.Errorf("failed to chdir to bazel workspace (%s): %v", bazelWorkspace, err)
		}
		return nil
	}
	cmd := exec.Command("git", "rev-parse", "--show-toplevel")
	output, err := cmd.Output()
	if err != nil {
		return err
	}
	d := strings.TrimSpace(string(output))
	logrus.Infof("Changing working directory to %s...", d)
	return os.Chdir(d)
}

type options struct {
	githubLogin string
	githubToken string
	gitName     string
	gitEmail    string
}

func parseOptions() options {
	var o options
	flag.StringVar(&o.githubLogin, "github-login", "", "The GitHub username to use.")
	flag.StringVar(&o.githubToken, "github-token", "", "The path to the GitHub token file.")
	flag.StringVar(&o.gitName, "git-name", "", "The name to use on the git commit. Requires --git-email. If not specified, uses values from the user associated with the access token.")
	flag.StringVar(&o.gitEmail, "git-email", "", "The email to use on the git commit. Requires --git-name. If not specified, uses values from the user associated with the access token.")
	flag.Parse()
	return o
}

func validateOptions(o options) error {
	if o.githubToken == "" {
		return fmt.Errorf("--github-token is mandatory")
	}
	if (o.gitEmail == "") != (o.gitName == "") {
		return fmt.Errorf("--git-name and --git-email must be specified together")
	}
	return nil
}

func getOncaller() (string, error) {
	req, err := http.Get(oncallAddress)
	if err != nil {
		return "", err
	}
	defer req.Body.Close()
	if req.StatusCode != http.StatusOK {
		return "", fmt.Errorf("HTTP error %d (%q) fetching current oncaller", req.StatusCode, req.Status)
	}
	oncall := struct {
		Oncall struct {
			TestInfra string `json:"testinfra"`
		} `json:"Oncall"`
	}{}
	if err := json.NewDecoder(req.Body).Decode(&oncall); err != nil {
		return "", err
	}
	return oncall.Oncall.TestInfra, nil
}

func getAssignment() string {
	oncaller, err := getOncaller()
	if err == nil {
		if oncaller != "" {
			return "/cc @" + oncaller
		}
		return "Nobody is currently oncall, so falling back to Blunderbuss."
	}
	return fmt.Sprintf("An error occurred while finding an assignee: `%s`.\nFalling back to Blunderbuss.", err)
}

func main() {
	o := parseOptions()
	if err := validateOptions(o); err != nil {
		logrus.WithError(err).Fatal("Invalid arguments.")
	}

	sa := &secret.Agent{}
	if err := sa.Start([]string{o.githubToken}); err != nil {
		logrus.WithError(err).Fatal("Failed to start secrets agent")
	}

	gc := github.NewClient(sa.GetTokenGenerator(o.githubToken), sa.Censor, github.DefaultGraphQLEndpoint, github.DefaultAPIEndpoint)

	if o.githubLogin == "" || o.gitName == "" || o.gitEmail == "" {
		user, err := gc.BotUser()
		if err != nil {
			logrus.WithError(err).Fatal("Failed to get the user data for the provided GH token.")
		}
		if o.githubLogin == "" {
			o.githubLogin = user.Login
		}
		if o.gitName == "" {
			o.gitName = user.Name
		}
		if o.gitEmail == "" {
			o.gitEmail = user.Email
		}
	}

	stdout := bumper.HideSecretsWriter{Delegate: os.Stdout, Censor: sa}
	stderr := bumper.HideSecretsWriter{Delegate: os.Stderr, Censor: sa}

	if err := cdToRootDir(); err != nil {
		logrus.WithError(err).Fatal("Failed to change to root dir")
	}
	images, err := bumper.UpdateReferences([]string{"."}, extraFiles)
	if err != nil {
		logrus.WithError(err).Fatal("Failed to update references.")
	}

	changed, err := bumper.HasChanges()
	if err != nil {
		logrus.WithError(err).Fatal("error occurred when checking changes")
	}

	if !changed {
		logrus.Info("no images updated, exiting ...")
		return
	}

	remoteBranch := "autobump"

	if err := bumper.MakeGitCommit(fmt.Sprintf("git@github.com:%s/test-infra.git", o.githubLogin), remoteBranch, o.gitName, o.gitEmail, images, stdout, stderr); err != nil {
		logrus.WithError(err).Fatal("Failed to push changes.")
	}

	if err := bumper.UpdatePR(gc, githubOrg, githubRepo, images, getAssignment(), "Update prow to", o.githubLogin+":"+remoteBranch, "master"); err != nil {
		logrus.WithError(err).Fatal("PR creation failed.")
	}
}
<commit_msg>Add kops grid generator to autobumper<commit_after>/*
Copyright 2019 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"os"
	"os/exec"
	"strings"

	"github.com/sirupsen/logrus"

	"k8s.io/test-infra/experiment/autobumper/bumper"
	"k8s.io/test-infra/prow/config/secret"
	"k8s.io/test-infra/prow/github"
)

const (
	oncallAddress = "https://storage.googleapis.com/kubernetes-jenkins/oncall.json"
	githubOrg     = "kubernetes"
	githubRepo    = "test-infra"
)

var extraFiles = map[string]bool{
	"config/jobs/kubernetes/kops/build-grid.py": true,
	"releng/generate_tests.py":                  true,
	"images/kubekins-e2e/Dockerfile":            true,
}

func cdToRootDir() error {
	if bazelWorkspace := os.Getenv("BUILD_WORKSPACE_DIRECTORY"); bazelWorkspace != "" {
		if err := os.Chdir(bazelWorkspace); err != nil {
			return fmt.Errorf("failed to chdir to bazel workspace (%s): %v", bazelWorkspace, err)
		}
		return nil
	}
	cmd := exec.Command("git", "rev-parse", "--show-toplevel")
	output, err := cmd.Output()
	if err != nil {
		return err
	}
	d := strings.TrimSpace(string(output))
	logrus.Infof("Changing working directory to %s...", d)
	return os.Chdir(d)
}

type options struct {
	githubLogin string
	githubToken string
	gitName     string
	gitEmail    string
}

func parseOptions() options {
	var o options
	flag.StringVar(&o.githubLogin, "github-login", "", "The GitHub username to use.")
	flag.StringVar(&o.githubToken, "github-token", "", "The path to the GitHub token file.")
	flag.StringVar(&o.gitName, "git-name", "", "The name to use on the git commit. Requires --git-email. If not specified, uses values from the user associated with the access token.")
	flag.StringVar(&o.gitEmail, "git-email", "", "The email to use on the git commit. Requires --git-name. If not specified, uses values from the user associated with the access token.")
	flag.Parse()
	return o
}

func validateOptions(o options) error {
	if o.githubToken == "" {
		return fmt.Errorf("--github-token is mandatory")
	}
	if (o.gitEmail == "") != (o.gitName == "") {
		return fmt.Errorf("--git-name and --git-email must be specified together")
	}
	return nil
}

func getOncaller() (string, error) {
	req, err := http.Get(oncallAddress)
	if err != nil {
		return "", err
	}
	defer req.Body.Close()
	if req.StatusCode != http.StatusOK {
		return "", fmt.Errorf("HTTP error %d (%q) fetching current oncaller", req.StatusCode, req.Status)
	}
	oncall := struct {
		Oncall struct {
			TestInfra string `json:"testinfra"`
		} `json:"Oncall"`
	}{}
	if err := json.NewDecoder(req.Body).Decode(&oncall); err != nil {
		return "", err
	}
	return oncall.Oncall.TestInfra, nil
}

func getAssignment() string {
	oncaller, err := getOncaller()
	if err == nil {
		if oncaller != "" {
			return "/cc @" + oncaller
		}
		return "Nobody is currently oncall, so falling back to Blunderbuss."
	}
	return fmt.Sprintf("An error occurred while finding an assignee: `%s`.\nFalling back to Blunderbuss.", err)
}

func main() {
	o := parseOptions()
	if err := validateOptions(o); err != nil {
		logrus.WithError(err).Fatal("Invalid arguments.")
	}

	sa := &secret.Agent{}
	if err := sa.Start([]string{o.githubToken}); err != nil {
		logrus.WithError(err).Fatal("Failed to start secrets agent")
	}

	gc := github.NewClient(sa.GetTokenGenerator(o.githubToken), sa.Censor, github.DefaultGraphQLEndpoint, github.DefaultAPIEndpoint)

	if o.githubLogin == "" || o.gitName == "" || o.gitEmail == "" {
		user, err := gc.BotUser()
		if err != nil {
			logrus.WithError(err).Fatal("Failed to get the user data for the provided GH token.")
		}
		if o.githubLogin == "" {
			o.githubLogin = user.Login
		}
		if o.gitName == "" {
			o.gitName = user.Name
		}
		if o.gitEmail == "" {
			o.gitEmail = user.Email
		}
	}

	stdout := bumper.HideSecretsWriter{Delegate: os.Stdout, Censor: sa}
	stderr := bumper.HideSecretsWriter{Delegate: os.Stderr, Censor: sa}

	if err := cdToRootDir(); err != nil {
		logrus.WithError(err).Fatal("Failed to change to root dir")
	}
	images, err := bumper.UpdateReferences([]string{"."}, extraFiles)
	if err != nil {
		logrus.WithError(err).Fatal("Failed to update references.")
	}

	changed, err := bumper.HasChanges()
	if err != nil {
		logrus.WithError(err).Fatal("error occurred when checking changes")
	}

	if !changed {
		logrus.Info("no images updated, exiting ...")
		return
	}

	remoteBranch := "autobump"

	if err := bumper.MakeGitCommit(fmt.Sprintf("git@github.com:%s/test-infra.git", o.githubLogin), remoteBranch, o.gitName, o.gitEmail, images, stdout, stderr); err != nil {
		logrus.WithError(err).Fatal("Failed to push changes.")
	}

	if err := bumper.UpdatePR(gc, githubOrg, githubRepo, images, getAssignment(), "Update prow to", o.githubLogin+":"+remoteBranch, "master"); err != nil {
		logrus.WithError(err).Fatal("PR creation failed.")
	}
}
<|endoftext|>


<commit_before>package gilibot

import (
	slack "github.com/alexandrebodin/slack_rtm"
	"log"
	"os"
)

type slackAdapter struct {
	bot *Bot
}

func NewSlackAdapter(b *Bot) *slackAdapter {
	return &slackAdapter{bot: b}
}

type slackHandler struct{}

func (h *slackHandler) OnMessage(c *slack.SlackContext, m *slack.MessageType) error {

	r := slack.ResponseMessage{
		Id:      "1",
		Type:    "message",
		Text:    "Coucou les copains",
		Channel: m.Channel,
	}
	c.Client.WriteMessage(r)
	return nil
}

func (s *slackAdapter) Start() error {

	token := os.Getenv("GILIBOT_SLACK_TOKEN")
	if token == "" {
		log.Fatal("slack token is missing")
	}

	slackClient, err := slack.New(token)
	if err != nil {
		return err
	}

	h := &slackHandler{}
	slackClient.AddListener(slack.MessageEvent, h)

	err = slackClient.Run()
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>add receive message to slack<commit_after>package gilibot

import (
	slack "github.com/alexandrebodin/slack_rtm"
	"log"
	"os"
)

type slackAdapter struct {
	bot *Bot
}

func NewSlackAdapter(b *Bot) *slackAdapter {
	return &slackAdapter{bot: b}
}

type slackHandler struct {
	bot *Bot
}

func (h *slackHandler) OnMessage(c *slack.SlackContext, m *slack.MessageType) error {

	h.bot.ReceiveMessage(m.Text)
	return nil
}

func (s *slackAdapter) Start() error {

	token := os.Getenv("GILIBOT_SLACK_TOKEN")
	if token == "" {
		log.Fatal("slack token is missing")
	}

	slackClient, err := slack.New(token)
	if err != nil {
		return err
	}

	h := &slackHandler{bot: s.bot}
	slackClient.AddListener(slack.MessageEvent, h)

	err = slackClient.Run()
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package nomad

import (
	"fmt"
	"testing"
	"time"

	memdb "github.com/hashicorp/go-memdb"
	"github.com/hashicorp/net-rpc-msgpackrpc"
	"github.com/hashicorp/nomad/nomad/mock"
	"github.com/hashicorp/nomad/nomad/structs"
	"github.com/hashicorp/nomad/testutil"
	"github.com/stretchr/testify/require"
)

func TestHeartbeat_InitializeHeartbeatTimers(t *testing.T) {
	t.Parallel()
	s1 := testServer(t, nil)
	defer s1.Shutdown()
	testutil.WaitForLeader(t, s1.RPC)

	node := mock.Node()
	state := s1.fsm.State()
	err := state.UpsertNode(1, node)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// Reset the heartbeat timers
	err = s1.initializeHeartbeatTimers()
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// Check that we have a timer
	_, ok := s1.heartbeatTimers[node.ID]
	if !ok {
		t.Fatalf("missing heartbeat timer")
	}
}

func TestHeartbeat_ResetHeartbeatTimer(t *testing.T) {
	t.Parallel()
	s1 := testServer(t, nil)
	defer s1.Shutdown()
	testutil.WaitForLeader(t, s1.RPC)

	// Create a new timer
	ttl, err := s1.resetHeartbeatTimer("test")
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL {
		t.Fatalf("bad: %#v", ttl)
	}

	// Check that we have a timer
	_, ok := s1.heartbeatTimers["test"]
	if !ok {
		t.Fatalf("missing heartbeat timer")
	}
}

func TestHeartbeat_ResetHeartbeatTimer_Nonleader(t *testing.T) {
	t.Parallel()
	require := require.New(t)
	s1 := testServer(t, func(c *Config) {
		c.BootstrapExpect = 3 // Won't become leader
		c.DevDisableBootstrap = true
	})
	defer s1.Shutdown()

	require.False(s1.IsLeader())

	// Create a new timer
	_, err := s1.resetHeartbeatTimer("test")
	require.NotNil(err)
	require.EqualError(err, heartbeatNotLeader)
}

func TestHeartbeat_ResetHeartbeatTimerLocked(t *testing.T) {
	t.Parallel()
	s1 := testServer(t, nil)
	defer s1.Shutdown()
	testutil.WaitForLeader(t, s1.RPC)

	s1.heartbeatTimersLock.Lock()
	s1.resetHeartbeatTimerLocked("foo", 5*time.Millisecond)
	s1.heartbeatTimersLock.Unlock()

	if _, ok := s1.heartbeatTimers["foo"]; !ok {
		t.Fatalf("missing timer")
	}

	time.Sleep(time.Duration(testutil.TestMultiplier()*10) * time.Millisecond)

	if _, ok := s1.heartbeatTimers["foo"]; ok {
		t.Fatalf("timer should be gone")
	}
}

func TestHeartbeat_ResetHeartbeatTimerLocked_Renew(t *testing.T) {
	t.Parallel()
	s1 := testServer(t, nil)
	defer s1.Shutdown()
	testutil.WaitForLeader(t, s1.RPC)

	s1.heartbeatTimersLock.Lock()
	s1.resetHeartbeatTimerLocked("foo", 30*time.Millisecond)
	s1.heartbeatTimersLock.Unlock()

	if _, ok := s1.heartbeatTimers["foo"]; !ok {
		t.Fatalf("missing timer")
	}

	time.Sleep(2 * time.Millisecond)

	// Renew the heartbeat
	s1.heartbeatTimersLock.Lock()
	s1.resetHeartbeatTimerLocked("foo", 30*time.Millisecond)
	s1.heartbeatTimersLock.Unlock()
	renew := time.Now()

	// Watch for invalidation
	for time.Now().Sub(renew) < time.Duration(testutil.TestMultiplier()*100)*time.Millisecond {
		s1.heartbeatTimersLock.Lock()
		_, ok := s1.heartbeatTimers["foo"]
		s1.heartbeatTimersLock.Unlock()
		if !ok {
			end := time.Now()
			if diff := end.Sub(renew); diff < 30*time.Millisecond {
				t.Fatalf("early invalidate %v", diff)
			}
			return
		}
		time.Sleep(2 * time.Millisecond)
	}
	t.Fatalf("should have expired")
}

func TestHeartbeat_InvalidateHeartbeat(t *testing.T) {
	t.Parallel()
	s1 := testServer(t, nil)
	defer s1.Shutdown()
	testutil.WaitForLeader(t, s1.RPC)

	// Create a node
	node := mock.Node()
	state := s1.fsm.State()
	err := state.UpsertNode(1, node)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// This should cause a status update
	s1.invalidateHeartbeat(node.ID)

	// Check it is updated
	ws := memdb.NewWatchSet()
	out, err := state.NodeByID(ws, node.ID)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if !out.TerminalStatus() {
		t.Fatalf("should update node: %#v", out)
	}
}

func TestHeartbeat_ClearHeartbeatTimer(t *testing.T) {
	t.Parallel()
	s1 := testServer(t, nil)
	defer s1.Shutdown()
	testutil.WaitForLeader(t, s1.RPC)

	s1.heartbeatTimersLock.Lock()
	s1.resetHeartbeatTimerLocked("foo", 5*time.Millisecond)
	s1.heartbeatTimersLock.Unlock()

	err := s1.clearHeartbeatTimer("foo")
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	if _, ok := s1.heartbeatTimers["foo"]; ok {
		t.Fatalf("timer should be gone")
	}
}

func TestHeartbeat_ClearAllHeartbeatTimers(t *testing.T) {
	t.Parallel()
	s1 := testServer(t, nil)
	defer s1.Shutdown()
	testutil.WaitForLeader(t, s1.RPC)

	s1.heartbeatTimersLock.Lock()
	s1.resetHeartbeatTimerLocked("foo", 10*time.Millisecond)
	s1.resetHeartbeatTimerLocked("bar", 10*time.Millisecond)
	s1.resetHeartbeatTimerLocked("baz", 10*time.Millisecond)
	s1.heartbeatTimersLock.Unlock()

	err := s1.clearAllHeartbeatTimers()
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	if len(s1.heartbeatTimers) != 0 {
		t.Fatalf("timers should be gone")
	}
}

func TestHeartbeat_Server_HeartbeatTTL_Failover(t *testing.T) {
	t.Parallel()
	s1 := testServer(t, nil)
	defer s1.Shutdown()

	s2 := testServer(t, func(c *Config) {
		c.DevDisableBootstrap = true
	})
	defer s2.Shutdown()

	s3 := testServer(t, func(c *Config) {
		c.DevDisableBootstrap = true
	})
	defer s3.Shutdown()
	servers := []*Server{s1, s2, s3}
	testJoin(t, s1, s2, s3)

	testutil.WaitForResult(func() (bool, error) {
		peers, _ := s1.numPeers()
		return peers == 3, nil
	}, func(err error) {
		t.Fatalf("should have 3 peers")
	})

	// Find the leader
	var leader *Server
	for _, s := range servers {
		// Check that s.heartbeatTimers is empty
		if len(s.heartbeatTimers) != 0 {
			t.Fatalf("should have no heartbeatTimers")
		}
		// Find the leader too
		if s.IsLeader() {
			leader = s
		}
	}
	if leader == nil {
		t.Fatalf("Should have a leader")
	}
	codec := rpcClient(t, leader)

	// Create the register request
	node := mock.Node()
	req := &structs.NodeRegisterRequest{
		Node:         node,
		WriteRequest: structs.WriteRequest{Region: "global"},
	}

	// Fetch the response
	var resp structs.GenericResponse
	if err := msgpackrpc.CallWithCodec(codec, "Node.Register", req, &resp); err != nil {
		t.Fatalf("err: %v", err)
	}

	// Check that heartbeatTimers has the heartbeat ID
	if _, ok := leader.heartbeatTimers[node.ID]; !ok {
		t.Fatalf("missing heartbeat timer")
	}

	// Shutdown the leader!
	leader.Shutdown()

	// heartbeatTimers should be cleared on leader shutdown
	if len(leader.heartbeatTimers) != 0 {
		t.Fatalf("heartbeat timers should be empty on the shutdown leader")
	}

	// Find the new leader
	testutil.WaitForResult(func() (bool, error) {
		leader = nil
		for _, s := range servers {
			if s.IsLeader() {
				leader = s
			}
		}
		if leader == nil {
			return false, fmt.Errorf("Should have a new leader")
		}

		// Ensure heartbeat timer is restored
		if _, ok := leader.heartbeatTimers[node.ID]; !ok {
			return false, fmt.Errorf("missing heartbeat timer")
		}

		return true, nil
	}, func(err error) {
		t.Fatalf("err: %s", err)
	})
}
<commit_msg>Fix flaky test<commit_after>package nomad

import (
	"fmt"
	"testing"
	"time"

	memdb "github.com/hashicorp/go-memdb"
	"github.com/hashicorp/net-rpc-msgpackrpc"
	"github.com/hashicorp/nomad/nomad/mock"
	"github.com/hashicorp/nomad/nomad/structs"
	"github.com/hashicorp/nomad/testutil"
	"github.com/stretchr/testify/require"
)

func TestHeartbeat_InitializeHeartbeatTimers(t *testing.T) {
	t.Parallel()
	s1 := testServer(t, nil)
	defer s1.Shutdown()
	testutil.WaitForLeader(t, s1.RPC)

	node := mock.Node()
	state := s1.fsm.State()
	err := state.UpsertNode(1, node)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// Reset the heartbeat timers
	err = s1.initializeHeartbeatTimers()
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// Check that we have a timer
	_, ok := s1.heartbeatTimers[node.ID]
	if !ok {
		t.Fatalf("missing heartbeat timer")
	}
}

func TestHeartbeat_ResetHeartbeatTimer(t *testing.T) {
	t.Parallel()
	s1 := testServer(t, nil)
	defer s1.Shutdown()
	testutil.WaitForLeader(t, s1.RPC)

	// Create a new timer
	ttl, err := s1.resetHeartbeatTimer("test")
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL {
		t.Fatalf("bad: %#v", ttl)
	}

	// Check that we have a timer
	_, ok := s1.heartbeatTimers["test"]
	if !ok {
		t.Fatalf("missing heartbeat timer")
	}
}

func TestHeartbeat_ResetHeartbeatTimer_Nonleader(t *testing.T) {
	t.Parallel()
	require := require.New(t)
	s1 := testServer(t, func(c *Config) {
		c.BootstrapExpect = 3 // Won't become leader
		c.DevDisableBootstrap = true
	})
	defer s1.Shutdown()

	require.False(s1.IsLeader())

	// Create a new timer
	_, err := s1.resetHeartbeatTimer("test")
	require.NotNil(err)
	require.EqualError(err, heartbeatNotLeader)
}

func TestHeartbeat_ResetHeartbeatTimerLocked(t *testing.T) {
	t.Parallel()
	s1 := testServer(t, nil)
	defer s1.Shutdown()
	testutil.WaitForLeader(t, s1.RPC)

	s1.heartbeatTimersLock.Lock()
	s1.resetHeartbeatTimerLocked("foo", 5*time.Millisecond)
	s1.heartbeatTimersLock.Unlock()

	if _, ok := s1.heartbeatTimers["foo"]; !ok {
		t.Fatalf("missing timer")
	}

	time.Sleep(time.Duration(testutil.TestMultiplier()*10) * time.Millisecond)

	if _, ok := s1.heartbeatTimers["foo"]; ok {
		t.Fatalf("timer should be gone")
	}
}

func TestHeartbeat_ResetHeartbeatTimerLocked_Renew(t *testing.T) {
	t.Parallel()
	s1 := testServer(t, nil)
	defer s1.Shutdown()
	testutil.WaitForLeader(t, s1.RPC)

	s1.heartbeatTimersLock.Lock()
	s1.resetHeartbeatTimerLocked("foo", 30*time.Millisecond)
	s1.heartbeatTimersLock.Unlock()

	if _, ok := s1.heartbeatTimers["foo"]; !ok {
		t.Fatalf("missing timer")
	}

	time.Sleep(2 * time.Millisecond)

	// Renew the heartbeat
	s1.heartbeatTimersLock.Lock()
	s1.resetHeartbeatTimerLocked("foo", 30*time.Millisecond)
	s1.heartbeatTimersLock.Unlock()
	renew := time.Now()

	// Watch for invalidation
	for time.Now().Sub(renew) < time.Duration(testutil.TestMultiplier()*100)*time.Millisecond {
		s1.heartbeatTimersLock.Lock()
		_, ok := s1.heartbeatTimers["foo"]
		s1.heartbeatTimersLock.Unlock()
		if !ok {
			end := time.Now()
			if diff := end.Sub(renew); diff < 30*time.Millisecond {
				t.Fatalf("early invalidate %v", diff)
			}
			return
		}
		time.Sleep(2 * time.Millisecond)
	}
	t.Fatalf("should have expired")
}

func TestHeartbeat_InvalidateHeartbeat(t *testing.T) {
	t.Parallel()
	s1 := testServer(t, nil)
	defer s1.Shutdown()
	testutil.WaitForLeader(t, s1.RPC)

	// Create a node
	node := mock.Node()
	state := s1.fsm.State()
	err := state.UpsertNode(1, node)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// This should cause a status update
	s1.invalidateHeartbeat(node.ID)

	// Check it is updated
	ws := memdb.NewWatchSet()
	out, err := state.NodeByID(ws, node.ID)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if !out.TerminalStatus() {
		t.Fatalf("should update node: %#v", out)
	}
}

func TestHeartbeat_ClearHeartbeatTimer(t *testing.T) {
	t.Parallel()
	s1 := testServer(t, nil)
	defer s1.Shutdown()
	testutil.WaitForLeader(t, s1.RPC)

	s1.heartbeatTimersLock.Lock()
	s1.resetHeartbeatTimerLocked("foo", 5*time.Millisecond)
	s1.heartbeatTimersLock.Unlock()

	err := s1.clearHeartbeatTimer("foo")
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	if _, ok := s1.heartbeatTimers["foo"]; ok {
		t.Fatalf("timer should be gone")
	}
}

func TestHeartbeat_ClearAllHeartbeatTimers(t *testing.T) {
	t.Parallel()
	s1 := testServer(t, nil)
	defer s1.Shutdown()
	testutil.WaitForLeader(t, s1.RPC)

	s1.heartbeatTimersLock.Lock()
	s1.resetHeartbeatTimerLocked("foo", 10*time.Millisecond)
	s1.resetHeartbeatTimerLocked("bar", 10*time.Millisecond)
	s1.resetHeartbeatTimerLocked("baz", 10*time.Millisecond)
	s1.heartbeatTimersLock.Unlock()

	err := s1.clearAllHeartbeatTimers()
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	if len(s1.heartbeatTimers) != 0 {
		t.Fatalf("timers should be gone")
	}
}

func TestHeartbeat_Server_HeartbeatTTL_Failover(t *testing.T) {
	t.Parallel()
	s1 := testServer(t, nil)
	defer s1.Shutdown()

	s2 := testServer(t, func(c *Config) {
		c.DevDisableBootstrap = true
	})
	defer s2.Shutdown()

	s3 := testServer(t, func(c *Config) {
		c.DevDisableBootstrap = true
	})
	defer s3.Shutdown()
	servers := []*Server{s1, s2, s3}
	testJoin(t, s1, s2, s3)

	testutil.WaitForResult(func() (bool, error) {
		peers, _ := s1.numPeers()
		return peers == 3, nil
	}, func(err error) {
		t.Fatalf("should have 3 peers")
	})

	// Find the leader
	var leader *Server
	for _, s := range servers {
		// Check that s.heartbeatTimers is empty
		if len(s.heartbeatTimers) != 0 {
			t.Fatalf("should have no heartbeatTimers")
		}
		// Find the leader too
		if s.IsLeader() {
			leader = s
		}
	}
	if leader == nil {
		t.Fatalf("Should have a leader")
	}
	codec := rpcClient(t, leader)

	// Create the register request
	node := mock.Node()
	req := &structs.NodeRegisterRequest{
		Node:         node,
		WriteRequest: structs.WriteRequest{Region: "global"},
	}

	// Fetch the response
	var resp structs.GenericResponse
	if err := msgpackrpc.CallWithCodec(codec, "Node.Register", req, &resp); err != nil {
		t.Fatalf("err: %v", err)
	}

	// Check that heartbeatTimers has the heartbeat ID
	if _, ok := leader.heartbeatTimers[node.ID]; !ok {
		t.Fatalf("missing heartbeat timer")
	}

	// Shutdown the leader!
	leader.Shutdown()

	// heartbeatTimers should be cleared on leader shutdown
	testutil.WaitForResult(func() (bool, error) {
		return len(leader.heartbeatTimers) == 0, nil
	}, func(err error) {
		t.Fatalf("heartbeat timers should be empty on the shutdown leader")
	})

	// Find the new leader
	testutil.WaitForResult(func() (bool, error) {
		leader = nil
		for _, s := range servers {
			if s.IsLeader() {
				leader = s
			}
		}
		if leader == nil {
			return false, fmt.Errorf("Should have a new leader")
		}

		// Ensure heartbeat timer is restored
		if _, ok := leader.heartbeatTimers[node.ID]; !ok {
			return false, fmt.Errorf("missing heartbeat timer")
		}

		return true, nil
	}, func(err error) {
		t.Fatalf("err: %s", err)
	})
}
<|endoftext|>


<commit_before>package ccv2

import (
	"bytes"
	"encoding/json"

	"code.cloudfoundry.org/cli/api/cloudcontroller"
	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv2/internal"
)

// User represents a Cloud Controller User.
type User struct {
	GUID string
}

// userRequestBody represents the body of the request.
type userRequestBody struct {
	GUID string `json:"guid"`
}

// UnmarshalJSON helps unmarshal a Cloud Controller User response.
func (user *User) UnmarshalJSON(data []byte) error {
	var ccUser struct {
		Metadata internal.Metadata `json:"metadata"`
	}
	if err := json.Unmarshal(data, &ccUser); err != nil {
		return err
	}

	user.GUID = ccUser.Metadata.GUID
	return nil
}

// CreateUser creates a new Cloud Controller User from the provided UAA user
// ID.
func (client *Client) CreateUser(uaaUserID string) (User, Warnings, error) {
	bodyBytes, err := json.Marshal(userRequestBody{
		GUID: uaaUserID,
	})
	if err != nil {
		return User{}, nil, err
	}

	request, err := client.newHTTPRequest(requestOptions{
		RequestName: internal.PostUserRequest,
		Body:        bytes.NewReader(bodyBytes),
	})
	if err != nil {
		return User{}, nil, err
	}

	var user User
	response := cloudcontroller.Response{
		Result: &user,
	}

	err = client.connection.Make(request, &response)
	if err != nil {
		return User{}, response.Warnings, err
	}

	return user, response.Warnings, nil
}
<commit_msg>add documentation to User struct<commit_after>package ccv2

import (
	"bytes"
	"encoding/json"

	"code.cloudfoundry.org/cli/api/cloudcontroller"
	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv2/internal"
)

// User represents a Cloud Controller User.
type User struct {
	// GUID is the unique user identifier.
	GUID string
}

// userRequestBody represents the body of the request.
type userRequestBody struct {
	GUID string `json:"guid"`
}

// UnmarshalJSON helps unmarshal a Cloud Controller User response.
func (user *User) UnmarshalJSON(data []byte) error {
	var ccUser struct {
		Metadata internal.Metadata `json:"metadata"`
	}
	if err := json.Unmarshal(data, &ccUser); err != nil {
		return err
	}

	user.GUID = ccUser.Metadata.GUID
	return nil
}

// CreateUser creates a new Cloud Controller User from the provided UAA user
// ID.
func (client *Client) CreateUser(uaaUserID string) (User, Warnings, error) {
	bodyBytes, err := json.Marshal(userRequestBody{
		GUID: uaaUserID,
	})
	if err != nil {
		return User{}, nil, err
	}

	request, err := client.newHTTPRequest(requestOptions{
		RequestName: internal.PostUserRequest,
		Body:        bytes.NewReader(bodyBytes),
	})
	if err != nil {
		return User{}, nil, err
	}

	var user User
	response := cloudcontroller.Response{
		Result: &user,
	}

	err = client.connection.Make(request, &response)
	if err != nil {
		return User{}, response.Warnings, err
	}

	return user, response.Warnings, nil
}
<|endoftext|>


<commit_before>package wikipediapageview

import (
	"net/http"
	"time"

	"cloud.google.com/go/bigquery"
	"github.com/go-chi/chi/v5"
	"github.com/rs/zerolog/log"
	"google.golang.org/api/iterator"

	hd "github.com/nownabe/cloud-demos/api/pkg/handler"
)

type getJobResponse struct {
	Completed  bool               `json:"completed"`
	Error      string             `json:"error,omitempty"`
	Config     *config            `json:"config"`
	Statistics *statistics        `json:"statistics,omitempty"`
	Results    [][]bigquery.Value `json:"results,omitempty"`
}

type statistics struct {
	StartTime           time.Time `json:"start_time"`
	EndTime             time.Time `json:"end_time"`
	TotalBytesProcessed int64     `json:"total_bytes_processed"`
	CacheHit            bool      `json:"cache_hit"`
	InputRows           int64     `json:"input_rows"`
}

type config struct {
	Query      string                    `json:"query"`
	QueryCache bool                      `json:"query_cache"`
	Parameters []bigquery.QueryParameter `json:"parameters"`
}

func (h *handler) getJob(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	logger := log.Ctx(ctx)

	jobID := chi.URLParam(r, "jobID")

	job, err := h.Bigquery.JobFromID(ctx, jobID)
	if err != nil {
		hd.RespondErrorJSON(w, r, hd.Errorf(ctx,
			http.StatusInternalServerError,
			http.StatusText(http.StatusInternalServerError),
			"failed to get job: %w", err))
		return
	}

	logger.Debug().Msgf("job: %+v", job)

	js, err := job.Status(ctx)
	if err != nil {
		hd.RespondErrorJSON(w, r, hd.Errorf(ctx,
			http.StatusInternalServerError,
			http.StatusText(http.StatusInternalServerError),
			"failed to get job status: %w", err))
		return
	}

	logger.Debug().Msgf("js: %+v", job)

	jc, err := job.Config()
	if err != nil {
		hd.RespondErrorJSON(w, r, hd.Errorf(ctx,
			http.StatusInternalServerError,
			http.StatusText(http.StatusInternalServerError),
			"failed to get job config: %w", err))
		return
	}

	logger.Debug().Msgf("jc: %+v", job)

	qc, ok := jc.(*bigquery.QueryConfig)
	if !ok {
		hd.RespondErrorMessage(w, r,
			http.StatusBadRequest,
			"job id must be id of query job")
		return
	}

	logger.Debug().Msgf("qc: %+v", job)

	res := &getJobResponse{
		Completed: js.Done(),
		Config: &config{
			Query:      qc.Q,
			QueryCache: !qc.DisableQueryCache,
			Parameters: qc.Parameters,
		},
	}

	if !js.Done() {
		hd.RespondJSON(w, r, http.StatusOK, res)
		return
	}

	if js.Err() != nil {
		res.Error = js.Err().Error()
		hd.RespondJSON(w, r, http.StatusOK, res)
		return
	}

	qs, ok := js.Statistics.Details.(*bigquery.QueryStatistics)
	if !ok {
		hd.RespondErrorMessage(w, r,
			http.StatusBadRequest,
			"job id must be id of query job")
		return
	}

	logger.Debug().Msgf("qc: %+v", job)

	res.Statistics = &statistics{
		StartTime:           js.Statistics.StartTime,
		EndTime:             js.Statistics.EndTime,
		TotalBytesProcessed: js.Statistics.TotalBytesProcessed,
		CacheHit:            qs.CacheHit,
		InputRows:           qs.QueryPlan[0].RecordsRead,
	}

	logger.Debug().Msgf("qs.QueryPlan: %+v", qs.QueryPlan)

	it, err := job.Read(ctx)
	if err != nil {
		hd.RespondErrorJSON(w, r, hd.Errorf(ctx,
			http.StatusInternalServerError,
			http.StatusText(http.StatusInternalServerError),
			"failed to read job: %w", err))
		return
	}

	results := [][]bigquery.Value{}

	for {
		var row []bigquery.Value

		err := it.Next(&row)
		if err == iterator.Done {
			break
		} else if err != nil {
			hd.RespondErrorJSON(w, r, hd.Errorf(ctx,
				http.StatusInternalServerError,
				http.StatusText(http.StatusInternalServerError),
				"failed to get : %w", err))
			return
		}

		results = append(results, row)
	}

	res.Results = results

	hd.RespondJSON(w, r, http.StatusOK, res)
}
<commit_msg>:bug: [api] Handle no input query<commit_after>package wikipediapageview

import (
	"net/http"
	"time"

	"cloud.google.com/go/bigquery"
	"github.com/go-chi/chi/v5"
	"github.com/rs/zerolog/log"
	"google.golang.org/api/iterator"

	hd "github.com/nownabe/cloud-demos/api/pkg/handler"
)

type getJobResponse struct {
	Completed  bool               `json:"completed"`
	Error      string             `json:"error,omitempty"`
	Config     *config            `json:"config"`
	Statistics *statistics        `json:"statistics,omitempty"`
	Results    [][]bigquery.Value `json:"results,omitempty"`
}

type statistics struct {
	StartTime           time.Time `json:"start_time"`
	EndTime             time.Time `json:"end_time"`
	TotalBytesProcessed int64     `json:"total_bytes_processed"`
	CacheHit            bool      `json:"cache_hit"`
	InputRows           int64     `json:"input_rows"`
}

type config struct {
	Query      string                    `json:"query"`
	QueryCache bool                      `json:"query_cache"`
	Parameters []bigquery.QueryParameter `json:"parameters"`
}

func (h *handler) getJob(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	logger := log.Ctx(ctx)

	jobID := chi.URLParam(r, "jobID")

	job, err := h.Bigquery.JobFromID(ctx, jobID)
	if err != nil {
		hd.RespondErrorJSON(w, r, hd.Errorf(ctx,
			http.StatusInternalServerError,
			http.StatusText(http.StatusInternalServerError),
			"failed to get job: %w", err))
		return
	}

	logger.Debug().Msgf("job: %+v", job)

	js, err := job.Status(ctx)
	if err != nil {
		hd.RespondErrorJSON(w, r, hd.Errorf(ctx,
			http.StatusInternalServerError,
			http.StatusText(http.StatusInternalServerError),
			"failed to get job status: %w", err))
		return
	}

	logger.Debug().Msgf("js: %+v", job)

	jc, err := job.Config()
	if err != nil {
		hd.RespondErrorJSON(w, r, hd.Errorf(ctx,
			http.StatusInternalServerError,
			http.StatusText(http.StatusInternalServerError),
			"failed to get job config: %w", err))
		return
	}

	logger.Debug().Msgf("jc: %+v", job)

	qc, ok := jc.(*bigquery.QueryConfig)
	if !ok {
		hd.RespondErrorMessage(w, r,
			http.StatusBadRequest,
			"job id must be id of query job")
		return
	}

	logger.Debug().Msgf("qc: %+v", job)

	res := &getJobResponse{
		Completed: js.Done(),
		Config: &config{
			Query:      qc.Q,
			QueryCache: !qc.DisableQueryCache,
			Parameters: qc.Parameters,
		},
	}

	if !js.Done() {
		hd.RespondJSON(w, r, http.StatusOK, res)
		return
	}

	if js.Err() != nil {
		res.Error = js.Err().Error()
		hd.RespondJSON(w, r, http.StatusOK, res)
		return
	}

	qs, ok := js.Statistics.Details.(*bigquery.QueryStatistics)
	if !ok {
		hd.RespondErrorMessage(w, r,
			http.StatusBadRequest,
			"job id must be id of query job")
		return
	}

	logger.Debug().Msgf("qc: %+v", job)

	res.Statistics = &statistics{
		StartTime:           js.Statistics.StartTime,
		EndTime:             js.Statistics.EndTime,
		TotalBytesProcessed: js.Statistics.TotalBytesProcessed,
		CacheHit:            qs.CacheHit,
	}

	logger.Debug().Msgf("qs.QueryPlan: %+v", qs.QueryPlan)

	if qs.QueryPlan != nil && len(qs.QueryPlan) > 0 {
		res.Statistics.InputRows = qs.QueryPlan[0].RecordsRead
	} else {
		res.Statistics.InputRows = 0
	}

	it, err := job.Read(ctx)
	if err != nil {
		hd.RespondErrorJSON(w, r, hd.Errorf(ctx,
			http.StatusInternalServerError,
			http.StatusText(http.StatusInternalServerError),
			"failed to read job: %w", err))
		return
	}

	results := [][]bigquery.Value{}

	for {
		var row []bigquery.Value

		err := it.Next(&row)
		if err == iterator.Done {
			break
		} else if err != nil {
			hd.RespondErrorJSON(w, r, hd.Errorf(ctx,
				http.StatusInternalServerError,
				http.StatusText(http.StatusInternalServerError),
				"failed to get : %w", err))
			return
		}

		results = append(results, row)
	}

	res.Results = results

	hd.RespondJSON(w, r, http.StatusOK, res)
}
<|endoftext|>


<commit_before>//
// version.go -- contains srnd version strings
//

package srnd

import "fmt"

var major_version = 4
var minor_version = 0
var program_name = "srnd"

func Version() string {
	return fmt.Sprintf("%s version 2.%d.%d", program_name, major_version, minor_version)
}
<commit_msg>bump daemon version<commit_after>//
// version.go -- contains srnd version strings
//

package srnd

import "fmt"

var major_version = 5
var minor_version = 0
var program_name = "srnd"

func Version() string {
	return fmt.Sprintf("%s version 2.%d.%d", program_name, major_version, minor_version)
}
<|endoftext|>