<commit_before>package main

import (
	"database/sql"
	"encoding/json"
	"errors"
	"flag"
	_ "github.com/go-sql-driver/mysql"
	"github.com/xwb1989/sqlparser"
	"html/template"
	"log"
	"net/http"
	"strconv"
	"strings"
	"time"
)

var (
	contextPath string
	homeTempl   = template.Must(template.New("").Parse(homeHTML))
	port        int
	maxRows     int
	dataSource  string
)

func init() {
	contextPathArg := flag.String("contextPath", "", "context path")
	portArg := flag.Int("port", 8381, "Port to serve.")
	maxRowsArg := flag.Int("maxRows", 1000, "Max number of rows to return.")
	dataSourceArg := flag.String("dataSource", "user:pass@tcp(127.0.0.1:3306)/db?charset=utf8", "dataSource string.")

	flag.Parse()

	contextPath = *contextPathArg
	port = *portArg
	maxRows = *maxRowsArg
	dataSource = *dataSourceArg
}

func main() {
	http.HandleFunc(contextPath+"/", serveHome)
	http.HandleFunc(contextPath+"/query", serveQuery)
	http.HandleFunc(contextPath+"/searchDb", serveSearchDb)
	if err := http.ListenAndServe(":"+strconv.Itoa(port), nil); err != nil {
		log.Fatal(err)
	}
}

func serveHome(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path != contextPath+"/" {
		http.Error(w, "Not found", 404)
		return
	}
	if r.Method != "GET" {
		http.Error(w, "Method not allowed", 405)
		return
	}
	w.Header().Set("Content-Type", "text/html; charset=utf-8")

	v := struct {
		Something bool
	}{
		false,
	}
	err := homeTempl.Execute(w, &v)
	if err != nil {
		log.Println("template execute error", err)
		w.Write([]byte(err.Error()))
	}
}

type SearchResult struct {
	MerchantName string
	MerchantId   string
}

func serveSearchDb(w http.ResponseWriter, req *http.Request) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	searchKey := strings.TrimSpace(req.FormValue("searchKey"))
	if searchKey == "" {
		http.Error(w, "searchKey required", 405)
		return
	}

	searchSql := `SELECT MERCHANT_NAME, MERCHANT_ID
		FROM TR_F_MERCHANT WHERE MERCHANT_ID = '` + searchKey + `'
		OR MERCHANT_CODE = '` + searchKey + `'
		OR MERCHANT_NAME LIKE '%` + searchKey + `%'
		LIMIT 3`

	_, data, _, _, err := executeQuery(searchSql, dataSource)
	if err != nil {
		http.Error(w, err.Error(), 405)
		return
	}

	searchResult := make([]SearchResult, len(data))
	for i, v := range data {
		searchResult[i] = SearchResult{
			v[1],
			v[2],
		}
	}

	json.NewEncoder(w).Encode(searchResult)
}

type QueryResult struct {
	Headers       []string
	Rows          [][]string
	Error         string
	ExecutionTime string
	CostTime      string
}

func serveQuery(w http.ResponseWriter, req *http.Request) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	querySql := strings.TrimSpace(req.FormValue("sql"))
	tid := strings.TrimSpace(req.FormValue("tid"))

	dbDataSource, err := selectDb(tid)
	if err != nil {
		http.Error(w, err.Error(), 405)
		return
	}

	start := time.Now()
	sqlParseResult, err := sqlparser.Parse(querySql)
	_, isInsert := sqlParseResult.(*sqlparser.Insert)
	_, isDelete := sqlParseResult.(*sqlparser.Delete)
	_, isUpdate := sqlParseResult.(*sqlparser.Update)
	_, isSet := sqlParseResult.(*sqlparser.Set)
	if isInsert || isDelete || isUpdate || isSet {
		json.NewEncoder(w).Encode(QueryResult{
			Headers:       nil,
			Rows:          nil,
			Error:         "dangerous sql, please get authorized first!",
			ExecutionTime: start.Format("2006-01-02 15:04:05.000"),
			CostTime:      time.Since(start).String(),
		})
		log.Println("sql", querySql, "is not allowed because of insert/delete/update/set")
		return
	}

	header, data, executionTime, costTime, err := executeQuery(querySql, dbDataSource)
	var errMsg string
	if err != nil {
		errMsg = err.Error()
	}

	queryResult := QueryResult{
		Headers:       header,
		Rows:          data,
		Error:         errMsg,
		ExecutionTime: executionTime,
		CostTime:      costTime,
	}

	json.NewEncoder(w).Encode(queryResult)
}

func selectDb(tid string) (string, error) {
	queryDbSql := "SELECT DB_USERNAME, DB_PASSWORD, PROXY_IP, PROXY_PORT, DB_NAME FROM TR_F_DB WHERE MERCHANT_ID = '" + tid + "' LIMIT 1"

	_, data, _, _, err := executeQuery(queryDbSql, dataSource)
	if err != nil {
		return "", err
	}

	if len(data) == 0 {
		return "", errors.New("no db found")
	} else if len(data) > 1 {
		return "", errors.New("more than one db found")
	}

	row := data[0]

	// user:pass@tcp(127.0.0.1:3306)/db?charset=utf8
	return row[1] + ":" + row[2] + "@tcp(" + row[3] + ":" + row[4] + ")/" + row[5] + "?charset=utf8mb4,utf8&timeout=3s", nil
}

func executeQuery(querySql, dataSource string) ([]string /*header*/, [][]string /*data*/, string /*executionTime*/, string /*costTime*/, error) {
	db, err := sql.Open("mysql", dataSource)
	if err != nil {
		return nil, nil, "", "", err
	}
	defer db.Close()

	header, data, executionTime, costTime, err := query(db, querySql, maxRows)
	return header, data, executionTime, costTime, err
}

func query(db *sql.DB, query string, maxRows int) ([]string, [][]string, string, string, error) {
	log.Printf("querying: %s", query)
	start := time.Now()
	executionTime := start.Format("2006-01-02 15:04:05.000")
	rows, err := db.Query(query)

	costTime := time.Since(start).String()
	if err != nil {
		return nil, nil, executionTime, costTime, err
	}

	columns, err := rows.Columns()
	if err != nil {
		return nil, nil, executionTime, costTime, err
	}

	columnSize := len(columns)

	data := make([][]string, 0)

	for row := 1; rows.Next() && row <= maxRows; row++ {
		strValues := make([]sql.NullString, columnSize+1)
		strValues[0] = sql.NullString{strconv.Itoa(row), true}
		pointers := make([]interface{}, columnSize)
		for i := 0; i < columnSize; i++ {
			pointers[i] = &strValues[i+1]
		}
		if err := rows.Scan(pointers...); err != nil {
			return columns, data, executionTime, "", err
		}

		values := make([]string, columnSize+1)
		for i, v := range strValues {
			if v.Valid {
				values[i] = v.String
			} else {
				values[i] = "(null)"
			}
		}

		data = append(data, values)
	}

	costTime = time.Since(start).String()
	return columns, data, executionTime, costTime, nil
}

const homeHTML = `<!DOCTYPE html>

 <title>sql web</title>

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

<input type="text" placeholder="tid/tcode/name" class="searchKey">
<button class="searchButton">Find DB</button>

<textarea  class="sql" id="code" cols="120" rows="5">
SELECT NOW()
</textarea>
<button class="executeQuery">Run SQL</button><button class="clearQueryResult">Clear</button>

`
<commit_msg>save sql history<commit_after>package main

import (
	"database/sql"
	"encoding/json"
	"errors"
	"flag"
	_ "github.com/go-sql-driver/mysql"
	"github.com/xwb1989/sqlparser"
	"html/template"
	"log"
	"net/http"
	"strconv"
	"strings"
	"time"
	"os"
)

var (
	contextPath string
	homeTempl   = template.Must(template.New("").Parse(homeHTML))
	port        int
	maxRows     int
	dataSource  string
)

func init() {
	contextPathArg := flag.String("contextPath", "", "context path")
	portArg := flag.Int("port", 8381, "Port to serve.")
	maxRowsArg := flag.Int("maxRows", 1000, "Max number of rows to return.")
	dataSourceArg := flag.String("dataSource", "user:pass@tcp(127.0.0.1:3306)/db?charset=utf8", "dataSource string.")

	flag.Parse()

	contextPath = *contextPathArg
	port = *portArg
	maxRows = *maxRowsArg
	dataSource = *dataSourceArg
}

func main() {
	http.HandleFunc(contextPath+"/", serveHome)
	http.HandleFunc(contextPath+"/query", serveQuery)
	http.HandleFunc(contextPath+"/searchDb", serveSearchDb)
	http.HandleFunc(contextPath+"/sqlHistory", serveSqlHistory)
	if err := http.ListenAndServe(":"+strconv.Itoa(port), nil); err != nil {
		log.Fatal(err)
	}
}

func serveHome(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path != contextPath+"/" {
		http.Error(w, "Not found", 404)
		return
	}
	if r.Method != "GET" {
		http.Error(w, "Method not allowed", 405)
		return
	}
	w.Header().Set("Content-Type", "text/html; charset=utf-8")

	v := struct {
		Something bool
	}{
		false,
	}
	err := homeTempl.Execute(w, &v)
	if err != nil {
		log.Println("template execute error", err)
		w.Write([]byte(err.Error()))
	}
}

type SqlHistory struct {
	SqlTime string
	Sql     string
}

func serveSqlHistory(w http.ResponseWriter, req *http.Request) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")

	// histories := make([]SqlHistory,0)

}

func saveHistory(sql string) {
	sqlHistory := SqlHistory{
		time.Now().Format("2006-01-02 15:04:05.000"),
		sql,
	}
	json, _ := json.Marshal(sqlHistory)
	file, _ := os.OpenFile("sqlHistory.json", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0660)
	file.Write(json)
	file.WriteString("\n")
	file.Close()
}

type SearchResult struct {
	MerchantName string
	MerchantId   string
}

func serveSearchDb(w http.ResponseWriter, req *http.Request) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	searchKey := strings.TrimSpace(req.FormValue("searchKey"))
	if searchKey == "" {
		http.Error(w, "searchKey required", 405)
		return
	}

	searchSql := `SELECT MERCHANT_NAME, MERCHANT_ID
		FROM TR_F_MERCHANT WHERE MERCHANT_ID = '` + searchKey + `'
		OR MERCHANT_CODE = '` + searchKey + `'
		OR MERCHANT_NAME LIKE '%` + searchKey + `%'
		LIMIT 3`

	_, data, _, _, err := executeQuery(searchSql, dataSource)
	if err != nil {
		http.Error(w, err.Error(), 405)
		return
	}

	searchResult := make([]SearchResult, len(data))
	for i, v := range data {
		searchResult[i] = SearchResult{
			v[1],
			v[2],
		}
	}

	json.NewEncoder(w).Encode(searchResult)
}

type QueryResult struct {
	Headers       []string
	Rows          [][]string
	Error         string
	ExecutionTime string
	CostTime      string
}

func serveQuery(w http.ResponseWriter, req *http.Request) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	querySql := strings.TrimSpace(req.FormValue("sql"))
	tid := strings.TrimSpace(req.FormValue("tid"))

	dbDataSource, err := selectDb(tid)
	if err != nil {
		http.Error(w, err.Error(), 405)
		return
	}

	start := time.Now()
	sqlParseResult, err := sqlparser.Parse(querySql)
	_, isInsert := sqlParseResult.(*sqlparser.Insert)
	_, isDelete := sqlParseResult.(*sqlparser.Delete)
	_, isUpdate := sqlParseResult.(*sqlparser.Update)
	_, isSet := sqlParseResult.(*sqlparser.Set)
	if isInsert || isDelete || isUpdate || isSet {
		json.NewEncoder(w).Encode(QueryResult{
			Headers:       nil,
			Rows:          nil,
			Error:         "dangerous sql, please get authorized first!",
			ExecutionTime: start.Format("2006-01-02 15:04:05.000"),
			CostTime:      time.Since(start).String(),
		})
		log.Println("sql", querySql, "is not allowed because of insert/delete/update/set")
		return
	}

	header, data, executionTime, costTime, err := executeQuery(querySql, dbDataSource)
	var errMsg string
	if err != nil {
		errMsg = err.Error()
	}

	saveHistory(querySql)

	queryResult := QueryResult{
		Headers:       header,
		Rows:          data,
		Error:         errMsg,
		ExecutionTime: executionTime,
		CostTime:      costTime,
	}

	json.NewEncoder(w).Encode(queryResult)
}

func selectDb(tid string) (string, error) {
	queryDbSql := "SELECT DB_USERNAME, DB_PASSWORD, PROXY_IP, PROXY_PORT, DB_NAME FROM TR_F_DB WHERE MERCHANT_ID = '" + tid + "' LIMIT 1"

	_, data, _, _, err := executeQuery(queryDbSql, dataSource)
	if err != nil {
		return "", err
	}

	if len(data) == 0 {
		return "", errors.New("no db found")
	} else if len(data) > 1 {
		return "", errors.New("more than one db found")
	}

	row := data[0]

	// user:pass@tcp(127.0.0.1:3306)/db?charset=utf8
	return row[1] + ":" + row[2] + "@tcp(" + row[3] + ":" + row[4] + ")/" + row[5] + "?charset=utf8mb4,utf8&timeout=3s", nil
}

func executeQuery(querySql, dataSource string) ([]string /*header*/ , [][]string /*data*/ , string /*executionTime*/ , string /*costTime*/ , error) {
	db, err := sql.Open("mysql", dataSource)
	if err != nil {
		return nil, nil, "", "", err
	}
	defer db.Close()

	header, data, executionTime, costTime, err := query(db, querySql, maxRows)
	return header, data, executionTime, costTime, err
}

func query(db *sql.DB, query string, maxRows int) ([]string, [][]string, string, string, error) {
	log.Printf("querying: %s", query)
	start := time.Now()
	executionTime := start.Format("2006-01-02 15:04:05.000")
	rows, err := db.Query(query)

	costTime := time.Since(start).String()
	if err != nil {
		return nil, nil, executionTime, costTime, err
	}

	columns, err := rows.Columns()
	if err != nil {
		return nil, nil, executionTime, costTime, err
	}

	columnSize := len(columns)

	data := make([][]string, 0)

	for row := 1; rows.Next() && row <= maxRows; row++ {
		strValues := make([]sql.NullString, columnSize+1)
		strValues[0] = sql.NullString{strconv.Itoa(row), true}
		pointers := make([]interface{}, columnSize)
		for i := 0; i < columnSize; i++ {
			pointers[i] = &strValues[i+1]
		}
		if err := rows.Scan(pointers...); err != nil {
			return columns, data, executionTime, "", err
		}

		values := make([]string, columnSize+1)
		for i, v := range strValues {
			if v.Valid {
				values[i] = v.String
			} else {
				values[i] = "(null)"
			}
		}

		data = append(data, values)
	}

	costTime = time.Since(start).String()
	return columns, data, executionTime, costTime, nil
}

const homeHTML = `<!DOCTYPE html>

 <title>sql web</title>

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

	<input type="text" placeholder="tid/tcode/name" class="searchKey">
	<button class="searchButton">Find DB</button>

	<textarea  class="sql" id="code" cols="120" rows="5">
	-- input sql here
	</textarea>
	<button class="executeQuery">Run SQL</button>
	<button class="clearQueryResult">Clear</button>
	<button class="showSqlHistory">History</button>

`
<|endoftext|>


<commit_before>package unnoticed

import (
	"encoding/binary"
	"errors"
	"log"
	"os"
	"time"
)

const (
	BYTE   = 1
	SHORT  = 2
	INT    = 4
	LONG   = 8
	SINGLE = 4
	DOUBLE = 8
)

// readByte reads a single byte from f.
func readByte(f *os.File) (uint8, error) {
	buf := make([]byte, BYTE)
	_, err := f.Read(buf)
	return buf[0], err
}

// readShort reads a 2-byte unsigned integer from f.
func readShort(f *os.File) (uint16, error) {
	buf := make([]byte, SHORT)
	if _, err := f.Read(buf); err != nil {
		return 0, err
	}
	return binary.LittleEndian.Uint16(buf), nil
}

// readInt reads a 4-byte unsigned integer from f.
func readInt(f *os.File) (uint32, error) {
	buf := make([]byte, INT)
	if _, err := f.Read(buf); err != nil {
		return 0, err
	}
	return binary.LittleEndian.Uint32(buf), nil
}

// readLong reads an 8-byte unsigned integer from f.
func readLong(f *os.File) (uint64, error) {
	buf := make([]byte, LONG)
	if _, err := f.Read(buf); err != nil {
		return 0, err
	}
	return binary.LittleEndian.Uint64(buf), nil
}

// readBool reads a boolean from f.
func readBool(f *os.File) (bool, error) {
	n, err := readByte(f)
	return n != 0, err
}

// readULEB reads and decodes a ULEB128 number from f.
// https://en.wikipedia.org/wiki/LEB128#Decode_unsigned_integer
func readULEB(f *os.File) (uint, error) {
	n, shift := uint(0), uint(0)
	for {
		b8, err := readByte(f)
		if err != nil {
			return 0, err
		}
		b := uint(b8) // Convert to 8-bit.
		n |= ((b & 0x7f) << shift)
		if (b & 0x80) == 0 {
			break
		}
		shift += 7
	}
	return n, nil
}

// readString reads a variable-length string from f.
func readString(f *os.File) (string, error) {
	if b, err := readByte(f); err != nil {
		return "", err
	} else if b == 0 {
		return "", err
	}
	n, err := readULEB(f)
	if err != nil {
		return "", err
	}
	buf := make([]byte, n)
	if _, err := f.Read(buf); err != nil {
		return "", err
	}
	return string(buf), nil
}

// readScore reads a Score from f.
func readScore(f *os.File) (score *Score, err error) {
	score = new(Score)
	// There's no size field so we'll avoid early returns, although it's
	// unlikely that this will actually get us back on track.
	flag := false
	score.Mode, err = readByte(f)
	flag = flag || err != nil
	_, err = readInt(f)
	score.MHash, err = readString(f)
	flag = flag || err != nil
	score.Name, err = readString(f)
	flag = flag || err != nil
	score.SHash, err = readString(f)
	flag = flag || err != nil
	score.N300, err = readShort(f)
	flag = flag || err != nil
	score.N100, err = readShort(f)
	flag = flag || err != nil
	score.N50, err = readShort(f)
	flag = flag || err != nil
	score.NGeki, err = readShort(f)
	flag = flag || err != nil
	score.NKatu, err = readShort(f)
	flag = flag || err != nil
	score.NMiss, err = readShort(f)
	flag = flag || err != nil
	score.Score, err = readInt(f)
	flag = flag || err != nil
	score.Combo, err = readShort(f)
	flag = flag || err != nil
	score.IsFC, err = readBool(f)
	flag = flag || err != nil
	score.Mods, err = readInt(f)
	flag = flag || err != nil
	_, err = readString(f) // This is supposedly always an empty string.
	flag = flag || err != nil
	ts, err := readLong(f)
	flag = flag || err != nil
	// https://stackoverflow.com/a/36120460/
	score.Date = time.Unix(0, int64(((ts)-60*60*24*365*1970*10000000)*100)).Unix()
	_, err = f.Seek(1*INT, 1) // This is supposedly always -1.
	flag = flag || err != nil
	_, err = readLong(f) // This is score ID, which is always 0 for unranked maps.
	flag = flag || err != nil

	if flag {
		return nil, errors.New("score parsing error")
	}
	return score, nil
}

// readScores reads all scores for one map.
func readScores(f *os.File) ([]*Score, error) {
	scores := []*Score{}
	md5, err := readString(f)
	if err != nil {
		return scores, err
	}
	nScores, err := readInt(f)
	if err != nil {
		return scores, err
	}

	for i := uint32(1); i <= nScores; i++ {
		if score, err := readScore(f); err != nil {
			log.Printf("score %d: %s\n", i, err)
		} else {
			scores = append(scores, score)
		}
	}

	for _, score := range scores {
		if score.MHash != md5 {
			log.Printf("mismatched beatmap MD5: expected %s, got %s\n", md5, score.MHash)
		}
	}

	return scores, err
}

// readMap reads a Beatmap from f.
func readMap(f *os.File, v uint32) (*Beatmap, error) {
	beatmap := new(Beatmap)
	start, err := f.Seek(0, 1) // Don't seek, just get the current place.
	if err != nil {
		return beatmap, err // If we return here, we're pretty much screwed.
	}
	size, err := readInt(f)
	if err != nil {
		return beatmap, err // This too.
	}
	defer f.Seek(start+int64(size)+4, 0)

	if _, err = readString(f); err != nil {
		return beatmap, err
	}
	if _, err = readString(f); err != nil {
		return beatmap, err
	}
	if _, err = readString(f); err != nil {
		return beatmap, err
	}
	if _, err = readString(f); err != nil {
		return beatmap, err
	}
	if _, err = readString(f); err != nil {
		return beatmap, err
	}
	if _, err = readString(f); err != nil {
		return beatmap, err
	}
	if _, err = readString(f); err != nil {
		return beatmap, err
	}
	if beatmap.MD5, err = readString(f); err != nil {
		return beatmap, err
	}
	if _, err = readString(f); err != nil {
		return beatmap, err
	}
	if beatmap.Status, err = readByte(f); err != nil {
		return beatmap, err
	}
	if _, err = f.Seek(3*SHORT+1*LONG, 1); err != nil {
		return beatmap, err
	}
	n := SINGLE
	if v < 20140609 {
		n = BYTE
	}
	if _, err = f.Seek(int64(4*n+1*DOUBLE), 1); err != nil {
		return beatmap, err
	}
	if v >= 20140609 {
		for i := 0; i < 4; i++ {
			nPairs, err := readInt(f)
			if err != nil {
				return beatmap, err
			}
			if _, err = f.Seek(int64(nPairs*14), 1); err != nil {
				return beatmap, err
			}
		}
	}
	if _, err = f.Seek(3*INT, 1); err != nil {
		return beatmap, err
	}
	nTimingPoints, err := readInt(f)
	if err != nil {
		return beatmap, err
	}
	if _, err = f.Seek(int64(nTimingPoints*17), 1); err != nil {
		return beatmap, err
	}
	if beatmap.ID, err = readInt(f); err != nil {
		return beatmap, err
	}
	if beatmap.ID == 0 {
		return beatmap, errors.New("beatmap id is 0")
	}

	return beatmap, err
}

// osuDB reads beatmaps from the osu! database file.
// https://osu.ppy.sh/help/wiki/osu!_File_Formats/Db_(file_format)
func osuDB(fn string) (string, []*Beatmap, error) {
	beatmaps := []*Beatmap{}
	username := ""
	f, err := os.Open(fn)
	if err != nil {
		return username, beatmaps, err
	}
	defer f.Close()

	v, err := readInt(f)
	if err != nil {
		return username, beatmaps, err
	}
	log.Printf("osu!.db version: %d\n", v)

	if _, err = f.Seek(1*INT+1*BYTE+1*LONG, 1); err != nil {
		return username, beatmaps, err
	}

	if username, err = readString(f); err != nil {
		return username, beatmaps, err
	}
	log.Printf("username: %s\n", username)

	nMaps, err := readInt(f)
	if err != nil {
		return username, beatmaps, err
	}
	log.Printf("osu.db contains %d beatmaps\n", nMaps)

	for i := 1; i <= int(nMaps); i++ {
		if beatmap, err := readMap(f, v); err != nil {
			log.Printf("map %d: %s\n", i, err)
		} else {
			beatmaps = append(beatmaps, beatmap)
		}
	}

	log.Printf("parsed %d/%d beatmaps\n", len(beatmaps), nMaps)
	return username, beatmaps, err
}

// scoresDB reads scores from the scores database file.
// https://osu.ppy.sh/help/wiki/osu!_File_Formats/Db_(file_format)
func scoresDB(fn string) ([]*Score, error) {
	scores := []*Score{}
	f, err := os.Open(fn)
	if err != nil {
		return scores, err
	}
	defer f.Close()

	v, err := readInt(f)
	if err != nil {
		return scores, err
	}
	log.Printf("scores.db version: %d\n", v)
	nMaps, err := readInt(f)
	if err != nil {
		return scores, err
	}
	log.Printf("scores.db contains %d beatmaps\n", nMaps)

	for i := uint32(1); i <= nMaps; i++ {
		if mapScores, err := readScores(f); err != nil {
			log.Printf("score %d: %s\n", err)
		} else {
			for _, score := range mapScores {
				scores = append(scores, score)
			}
		}
	}

	log.Printf("parsed %d scores for %d beatmaps\n", len(scores), nMaps)
	return scores, err
}

// BuildDB parses the osu!.db and scores.db files and builds a DB.
func BuildDB(scoresPath, osuPath string) (*DB, error) {
	db := new(DB)
	scores, err := scoresDB(scoresPath)
	if err != nil {
		return db, err
	}
	username, beatmaps, err := osuDB(osuPath)
	if err != nil {
		return db, err
	}
	return NewDB(username, scores, beatmaps), err
}
<commit_msg>Fix Windows tick -> Unix timestamp conversion<commit_after>package unnoticed

import (
	"encoding/binary"
	"errors"
	"log"
	"os"
)

const (
	BYTE   = 1
	SHORT  = 2
	INT    = 4
	LONG   = 8
	SINGLE = 4
	DOUBLE = 8
)

// readByte reads a single byte from f.
func readByte(f *os.File) (uint8, error) {
	buf := make([]byte, BYTE)
	_, err := f.Read(buf)
	return buf[0], err
}

// readShort reads a 2-byte unsigned integer from f.
func readShort(f *os.File) (uint16, error) {
	buf := make([]byte, SHORT)
	if _, err := f.Read(buf); err != nil {
		return 0, err
	}
	return binary.LittleEndian.Uint16(buf), nil
}

// readInt reads a 4-byte unsigned integer from f.
func readInt(f *os.File) (uint32, error) {
	buf := make([]byte, INT)
	if _, err := f.Read(buf); err != nil {
		return 0, err
	}
	return binary.LittleEndian.Uint32(buf), nil
}

// readLong reads an 8-byte unsigned integer from f.
func readLong(f *os.File) (uint64, error) {
	buf := make([]byte, LONG)
	if _, err := f.Read(buf); err != nil {
		return 0, err
	}
	return binary.LittleEndian.Uint64(buf), nil
}

// readBool reads a boolean from f.
func readBool(f *os.File) (bool, error) {
	n, err := readByte(f)
	return n != 0, err
}

// readULEB reads and decodes a ULEB128 number from f.
// https://en.wikipedia.org/wiki/LEB128#Decode_unsigned_integer
func readULEB(f *os.File) (uint, error) {
	n, shift := uint(0), uint(0)
	for {
		b8, err := readByte(f)
		if err != nil {
			return 0, err
		}
		b := uint(b8) // Convert to 8-bit.
		n |= ((b & 0x7f) << shift)
		if (b & 0x80) == 0 {
			break
		}
		shift += 7
	}
	return n, nil
}

// readString reads a variable-length string from f.
func readString(f *os.File) (string, error) {
	if b, err := readByte(f); err != nil {
		return "", err
	} else if b == 0 {
		return "", err
	}
	n, err := readULEB(f)
	if err != nil {
		return "", err
	}
	buf := make([]byte, n)
	if _, err := f.Read(buf); err != nil {
		return "", err
	}
	return string(buf), nil
}

// readScore reads a Score from f.
func readScore(f *os.File) (score *Score, err error) {
	score = new(Score)
	// There's no size field so we'll avoid early returns, although it's
	// unlikely that this will actually get us back on track.
	flag := false
	score.Mode, err = readByte(f)
	flag = flag || err != nil
	_, err = readInt(f)
	score.MHash, err = readString(f)
	flag = flag || err != nil
	score.Name, err = readString(f)
	flag = flag || err != nil
	score.SHash, err = readString(f)
	flag = flag || err != nil
	score.N300, err = readShort(f)
	flag = flag || err != nil
	score.N100, err = readShort(f)
	flag = flag || err != nil
	score.N50, err = readShort(f)
	flag = flag || err != nil
	score.NGeki, err = readShort(f)
	flag = flag || err != nil
	score.NKatu, err = readShort(f)
	flag = flag || err != nil
	score.NMiss, err = readShort(f)
	flag = flag || err != nil
	score.Score, err = readInt(f)
	flag = flag || err != nil
	score.Combo, err = readShort(f)
	flag = flag || err != nil
	score.IsFC, err = readBool(f)
	flag = flag || err != nil
	score.Mods, err = readInt(f)
	flag = flag || err != nil
	_, err = readString(f) // This is supposedly always an empty string.
	flag = flag || err != nil
	ts, err := readLong(f)
	flag = flag || err != nil
	// https://github.com/worldwidewat/TicksToDateTime/
	// Windows ticks don't overflow a signed int for a veeeeeery long time.
	score.Date = (int64(ts) - 621355968000000000) / 10000000
	_, err = f.Seek(1*INT, 1) // This is supposedly always -1.
	flag = flag || err != nil
	_, err = readLong(f) // This is score ID, which is always 0 for unranked maps.
	flag = flag || err != nil

	if flag {
		return nil, errors.New("score parsing error")
	}
	return score, nil
}

// readScores reads all scores for one map.
func readScores(f *os.File) ([]*Score, error) {
	scores := []*Score{}
	md5, err := readString(f)
	if err != nil {
		return scores, err
	}
	nScores, err := readInt(f)
	if err != nil {
		return scores, err
	}

	for i := uint32(1); i <= nScores; i++ {
		if score, err := readScore(f); err != nil {
			log.Printf("score %d: %s\n", i, err)
		} else {
			scores = append(scores, score)
		}
	}

	for _, score := range scores {
		if score.MHash != md5 {
			log.Printf("mismatched beatmap MD5: expected %s, got %s\n", md5, score.MHash)
		}
	}

	return scores, err
}

// readMap reads a Beatmap from f.
func readMap(f *os.File, v uint32) (*Beatmap, error) {
	beatmap := new(Beatmap)
	start, err := f.Seek(0, 1) // Don't seek, just get the current place.
	if err != nil {
		return beatmap, err // If we return here, we're pretty much screwed.
	}
	size, err := readInt(f)
	if err != nil {
		return beatmap, err // This too.
	}
	defer f.Seek(start+int64(size)+4, 0)

	if _, err = readString(f); err != nil {
		return beatmap, err
	}
	if _, err = readString(f); err != nil {
		return beatmap, err
	}
	if _, err = readString(f); err != nil {
		return beatmap, err
	}
	if _, err = readString(f); err != nil {
		return beatmap, err
	}
	if _, err = readString(f); err != nil {
		return beatmap, err
	}
	if _, err = readString(f); err != nil {
		return beatmap, err
	}
	if _, err = readString(f); err != nil {
		return beatmap, err
	}
	if beatmap.MD5, err = readString(f); err != nil {
		return beatmap, err
	}
	if _, err = readString(f); err != nil {
		return beatmap, err
	}
	if beatmap.Status, err = readByte(f); err != nil {
		return beatmap, err
	}
	if _, err = f.Seek(3*SHORT+1*LONG, 1); err != nil {
		return beatmap, err
	}
	n := SINGLE
	if v < 20140609 {
		n = BYTE
	}
	if _, err = f.Seek(int64(4*n+1*DOUBLE), 1); err != nil {
		return beatmap, err
	}
	if v >= 20140609 {
		for i := 0; i < 4; i++ {
			nPairs, err := readInt(f)
			if err != nil {
				return beatmap, err
			}
			if _, err = f.Seek(int64(nPairs*14), 1); err != nil {
				return beatmap, err
			}
		}
	}
	if _, err = f.Seek(3*INT, 1); err != nil {
		return beatmap, err
	}
	nTimingPoints, err := readInt(f)
	if err != nil {
		return beatmap, err
	}
	if _, err = f.Seek(int64(nTimingPoints*17), 1); err != nil {
		return beatmap, err
	}
	if beatmap.ID, err = readInt(f); err != nil {
		return beatmap, err
	}
	if beatmap.ID == 0 {
		return beatmap, errors.New("beatmap id is 0")
	}

	return beatmap, err
}

// osuDB reads beatmaps from the osu! database file.
// https://osu.ppy.sh/help/wiki/osu!_File_Formats/Db_(file_format)
func osuDB(fn string) (string, []*Beatmap, error) {
	beatmaps := []*Beatmap{}
	username := ""
	f, err := os.Open(fn)
	if err != nil {
		return username, beatmaps, err
	}
	defer f.Close()

	v, err := readInt(f)
	if err != nil {
		return username, beatmaps, err
	}
	log.Printf("osu!.db version: %d\n", v)

	if _, err = f.Seek(1*INT+1*BYTE+1*LONG, 1); err != nil {
		return username, beatmaps, err
	}

	if username, err = readString(f); err != nil {
		return username, beatmaps, err
	}
	log.Printf("username: %s\n", username)

	nMaps, err := readInt(f)
	if err != nil {
		return username, beatmaps, err
	}
	log.Printf("osu.db contains %d beatmaps\n", nMaps)

	for i := 1; i <= int(nMaps); i++ {
		if beatmap, err := readMap(f, v); err != nil {
			log.Printf("map %d: %s\n", i, err)
		} else {
			beatmaps = append(beatmaps, beatmap)
		}
	}

	log.Printf("parsed %d/%d beatmaps\n", len(beatmaps), nMaps)
	return username, beatmaps, err
}

// scoresDB reads scores from the scores database file.
// https://osu.ppy.sh/help/wiki/osu!_File_Formats/Db_(file_format)
func scoresDB(fn string) ([]*Score, error) {
	scores := []*Score{}
	f, err := os.Open(fn)
	if err != nil {
		return scores, err
	}
	defer f.Close()

	v, err := readInt(f)
	if err != nil {
		return scores, err
	}
	log.Printf("scores.db version: %d\n", v)
	nMaps, err := readInt(f)
	if err != nil {
		return scores, err
	}
	log.Printf("scores.db contains %d beatmaps\n", nMaps)

	for i := uint32(1); i <= nMaps; i++ {
		if mapScores, err := readScores(f); err != nil {
			log.Printf("score %d: %s\n", err)
		} else {
			for _, score := range mapScores {
				scores = append(scores, score)
			}
		}
	}

	log.Printf("parsed %d scores for %d beatmaps\n", len(scores), nMaps)
	return scores, err
}

// BuildDB parses the osu!.db and scores.db files and builds a DB.
func BuildDB(scoresPath, osuPath string) (*DB, error) {
	db := new(DB)
	scores, err := scoresDB(scoresPath)
	if err != nil {
		return db, err
	}
	username, beatmaps, err := osuDB(osuPath)
	if err != nil {
		return db, err
	}
	return NewDB(username, scores, beatmaps), err
}
<|endoftext|>


<commit_before>package role

import (
	"github.com/watermint/toolbox/domain/dropbox/api/dbx_auth"
	"github.com/watermint/toolbox/domain/dropbox/api/dbx_conn"
	"github.com/watermint/toolbox/domain/dropbox/model/mo_adminrole"
	"github.com/watermint/toolbox/domain/dropbox/model/mo_member"
	"github.com/watermint/toolbox/domain/dropbox/model/mo_user"
	"github.com/watermint/toolbox/domain/dropbox/service/sv_adminrole"
	"github.com/watermint/toolbox/domain/dropbox/service/sv_group"
	"github.com/watermint/toolbox/domain/dropbox/service/sv_group_member"
	"github.com/watermint/toolbox/domain/dropbox/service/sv_member"
	"github.com/watermint/toolbox/essentials/queue/eq_sequence"
	"github.com/watermint/toolbox/infra/control/app_control"
	"github.com/watermint/toolbox/infra/recipe/rc_exec"
	"github.com/watermint/toolbox/infra/recipe/rc_recipe"
	"github.com/watermint/toolbox/infra/report/rp_model"
)

type Delete struct {
	Peer           dbx_conn.ConnScopedTeam
	ExceptionGroup string
	RoleId         string
	Roles          rp_model.RowReport
}

func (z *Delete) Preset() {
	z.Peer.SetScopes(
		dbx_auth.ScopeGroupsRead,
		dbx_auth.ScopeMembersRead,
		dbx_auth.ScopeMembersWrite,
	)
	z.Roles.SetModel(
		&mo_adminrole.MemberRole{},
	)
}

func (z *Delete) reportRoles(member *mo_member.Member, roles []*mo_adminrole.Role) {
	for _, role := range roles {
		z.Roles.Row(mo_adminrole.NewMemberRole(member.TeamMemberId, member.Email, role))
	}
}

func (z *Delete) deleteRoleMember(member *mo_member.Member, c app_control.Control) error {
	newRoleIds := make([]string, 0)
	found := false
	roleIds := member.RoleIds()
	for _, roleId := range roleIds {
		if roleId == z.RoleId {
			found = true
		} else {
			newRoleIds = append(newRoleIds, roleId)
		}
	}

	if !found {
		return nil
	}

	updated, err := sv_adminrole.New(z.Peer.Context()).UpdateRole(mo_user.NewUserSelectorByTeamMemberId(member.TeamMemberId), newRoleIds)
	if err != nil {
		return err
	}

	z.reportRoles(member, updated)
	return nil
}

func (z *Delete) Exec(c app_control.Control) error {
	if err := z.Roles.Open(); err != nil {
		return err
	}

	group, err := sv_group.New(z.Peer.Context()).ResolveByName(z.ExceptionGroup)
	if err != nil {
		return err
	}
	exceptionMembers, err := sv_group_member.New(z.Peer.Context(), group).List()
	if err != nil {
		return err
	}

	isTargetMember := func(m *mo_member.Member) bool {
		for _, em := range exceptionMembers {
			if em.TeamMemberId == m.TeamMemberId {
				return false
			}
		}
		return true
	}

	var lastErr, listErr error
	c.Sequence().Do(func(s eq_sequence.Stage) {
		s.Define("delete_role", z.deleteRoleMember, c)
		q := s.Get("delete_role")

		listErr = sv_member.New(z.Peer.Context()).ListEach(func(member *mo_member.Member) bool {
			if isTargetMember(member) {
				q.Enqueue(member)
			}
			return true
		})
	}, eq_sequence.ErrorHandler(func(err error, mouldId, batchId string, p interface{}) {
		lastErr = err
	}))
	return lastErr
}

func (z *Delete) Test(c app_control.Control) error {
	return rc_exec.ExecMock(c, &Delete{}, func(r rc_recipe.Recipe) {
		m := r.(*Delete)
		m.ExceptionGroup = "CorpIt"
		m.RoleId = "pid_dbtmr:1234"
	})
}
<commit_msg>fix test<commit_after>package role

import (
	"github.com/watermint/toolbox/domain/dropbox/api/dbx_auth"
	"github.com/watermint/toolbox/domain/dropbox/api/dbx_conn"
	"github.com/watermint/toolbox/domain/dropbox/model/mo_adminrole"
	"github.com/watermint/toolbox/domain/dropbox/model/mo_member"
	"github.com/watermint/toolbox/domain/dropbox/model/mo_user"
	"github.com/watermint/toolbox/domain/dropbox/service/sv_adminrole"
	"github.com/watermint/toolbox/domain/dropbox/service/sv_group"
	"github.com/watermint/toolbox/domain/dropbox/service/sv_group_member"
	"github.com/watermint/toolbox/domain/dropbox/service/sv_member"
	"github.com/watermint/toolbox/essentials/lang"
	"github.com/watermint/toolbox/essentials/queue/eq_sequence"
	"github.com/watermint/toolbox/infra/control/app_control"
	"github.com/watermint/toolbox/infra/recipe/rc_exec"
	"github.com/watermint/toolbox/infra/recipe/rc_recipe"
	"github.com/watermint/toolbox/infra/report/rp_model"
)

type Delete struct {
	Peer           dbx_conn.ConnScopedTeam
	ExceptionGroup string
	RoleId         string
	Roles          rp_model.RowReport
}

func (z *Delete) Preset() {
	z.Peer.SetScopes(
		dbx_auth.ScopeGroupsRead,
		dbx_auth.ScopeMembersRead,
		dbx_auth.ScopeMembersWrite,
	)
	z.Roles.SetModel(
		&mo_adminrole.MemberRole{},
	)
}

func (z *Delete) reportRoles(member *mo_member.Member, roles []*mo_adminrole.Role) {
	for _, role := range roles {
		z.Roles.Row(mo_adminrole.NewMemberRole(member.TeamMemberId, member.Email, role))
	}
}

func (z *Delete) deleteRoleMember(member *mo_member.Member, c app_control.Control) error {
	newRoleIds := make([]string, 0)
	found := false
	roleIds := member.RoleIds()
	for _, roleId := range roleIds {
		if roleId == z.RoleId {
			found = true
		} else {
			newRoleIds = append(newRoleIds, roleId)
		}
	}

	if !found {
		return nil
	}

	updated, err := sv_adminrole.New(z.Peer.Context()).UpdateRole(mo_user.NewUserSelectorByTeamMemberId(member.TeamMemberId), newRoleIds)
	if err != nil {
		return err
	}

	z.reportRoles(member, updated)
	return nil
}

func (z *Delete) Exec(c app_control.Control) error {
	if err := z.Roles.Open(); err != nil {
		return err
	}

	group, err := sv_group.New(z.Peer.Context()).ResolveByName(z.ExceptionGroup)
	if err != nil {
		return err
	}
	exceptionMembers, err := sv_group_member.New(z.Peer.Context(), group).List()
	if err != nil {
		return err
	}

	isTargetMember := func(m *mo_member.Member) bool {
		for _, em := range exceptionMembers {
			if em.TeamMemberId == m.TeamMemberId {
				return false
			}
		}
		return true
	}

	var lastErr, listErr error
	c.Sequence().Do(func(s eq_sequence.Stage) {
		s.Define("delete_role", z.deleteRoleMember, c)
		q := s.Get("delete_role")

		listErr = sv_member.New(z.Peer.Context()).ListEach(func(member *mo_member.Member) bool {
			if isTargetMember(member) {
				q.Enqueue(member)
			}
			return true
		})
	}, eq_sequence.ErrorHandler(func(err error, mouldId, batchId string, p interface{}) {
		lastErr = err
	}))
	return lang.NewMultiErrorOrNull(lastErr, listErr)
}

func (z *Delete) Test(c app_control.Control) error {
	return rc_exec.ExecMock(c, &Delete{}, func(r rc_recipe.Recipe) {
		m := r.(*Delete)
		m.ExceptionGroup = "CorpIt"
		m.RoleId = "pid_dbtmr:1234"
	})
}
<|endoftext|>


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

package cmd

import (
	"fmt"
	"io"

	multierror "github.com/hashicorp/go-multierror"
	"github.com/spf13/cobra"
	"k8s.io/api/extensions/v1beta1"
	// gcp is needed for GKE cluster auth to work.
	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"

	"github.com/GoogleCloudPlatform/k8s-multicluster-ingress/app/kubemci/pkg/gcp/cloudinterface"
	gcplb "github.com/GoogleCloudPlatform/k8s-multicluster-ingress/app/kubemci/pkg/gcp/loadbalancer"
	gcputils "github.com/GoogleCloudPlatform/k8s-multicluster-ingress/app/kubemci/pkg/gcp/utils"
	"github.com/GoogleCloudPlatform/k8s-multicluster-ingress/app/kubemci/pkg/ingress"
	"github.com/GoogleCloudPlatform/k8s-multicluster-ingress/app/kubemci/pkg/kubeutils"
)

var (
	removeClustersShortDesc = "Remove an existing multicluster ingress from some clusters."
	removeClustersLongDesc  = `Remove an existing multicluster ingress from some clusters.

	Takes a load balancer name and a list of clusters and removes the existing multicluster ingress from those clusters.
	If the clusters have already been deleted, you can run "kubemci create --force" with the updated cluster list to update the
	load balancer to be restricted to those clusters. That will however not delete the ingress from old clusters (which is fine
	if the clusters have been deleted already).
`
)

type removeClustersOptions struct {
	// Name of the YAML file containing ingress spec.
	// Required.
	IngressFilename string
	// Path to kubeconfig file.
	// Required.
	KubeconfigFilename string
	// Names of the contexts to use from the kubeconfig file.
	KubeContexts []string
	// Name of the load balancer.
	// Required.
	LBName string
	// Name of the GCP project in which the load balancer is configured.
	GCPProject string
	// Overwrite values when they differ from what's requested. If
	// the resource does not exist, or is already the correct
	// value, then 'force' is a no-op.
	ForceUpdate bool
	// Name of the namespace for the ingress when none is provided (mismatch of option with spec causes an error).
	Namespace string
}

func newCmdRemoveClusters(out, err io.Writer) *cobra.Command {
	var options removeClustersOptions
	cmd := &cobra.Command{
		Use:   "remove-clusters",
		Short: removeClustersShortDesc,
		Long:  removeClustersLongDesc,
		Run: func(cmd *cobra.Command, args []string) {
			if err := validateRemoveClustersArgs(&options, args); err != nil {
				fmt.Println(err)
				return
			}
			if err := runRemoveClusters(&options, args); err != nil {
				fmt.Println("Error removing clusters:", err)
				return
			}
		},
	}
	addRemoveClustersFlags(cmd, &options)
	return cmd
}

func addRemoveClustersFlags(cmd *cobra.Command, options *removeClustersOptions) error {
	cmd.Flags().StringVarP(&options.IngressFilename, "ingress", "i", options.IngressFilename, "[required] filename containing ingress spec")
	cmd.Flags().StringVarP(&options.KubeconfigFilename, "kubeconfig", "k", options.KubeconfigFilename, "[required] path to kubeconfig file")
	cmd.Flags().StringSliceVar(&options.KubeContexts, "kubecontexts", options.KubeContexts, "[optional] contexts in the kubeconfig file to remove the ingress from")
	cmd.Flags().StringVarP(&options.GCPProject, "gcp-project", "", options.GCPProject, "[required] name of the gcp project")
	cmd.Flags().BoolVarP(&options.ForceUpdate, "force", "f", options.ForceUpdate, "[optional] overwrite existing settings if they are different")
	cmd.Flags().StringVarP(&options.Namespace, "namespace", "n", options.Namespace, "[optional] namespace for the ingress only if left unspecified by ingress spec")
	return nil
}

func validateRemoveClustersArgs(options *removeClustersOptions, args []string) error {
	if len(args) != 1 {
		return fmt.Errorf("unexpected args: %v. Expected one arg as name of load balancer", args)
	}
	// Verify that the required options are not missing.
	if options.IngressFilename == "" {
		return fmt.Errorf("unexpected missing argument ingress")
	}
	if options.GCPProject == "" {
		project, err := gcputils.GetProjectFromGCloud()
		if project == "" || err != nil {
			return fmt.Errorf("unexpected cannot determine GCP project. Either set --gcp-project flag, or set a default project with gcloud such that gcloud config get-value project returns that")
		}
		options.GCPProject = project
	}
	if options.KubeconfigFilename == "" {
		return fmt.Errorf("unexpected missing argument kubeconfig")
	}
	return nil
}

// runRemoveClusters removes the given load balancer from the given list of clusters.
func runRemoveClusters(options *removeClustersOptions, args []string) error {
	options.LBName = args[0]

	// Unmarshal the YAML into ingress struct.
	var ing v1beta1.Ingress
	if err := ingress.UnmarshallAndApplyDefaults(options.IngressFilename, options.Namespace, &ing); err != nil {
		return fmt.Errorf("error in unmarshalling the yaml file %s, err: %s", options.IngressFilename, err)
	}
	cloudInterface, err := cloudinterface.NewGCECloudInterface(options.GCPProject)
	if err != nil {
		err := fmt.Errorf("error in creating cloud interface: %s", err)
		fmt.Println(err)
		return err
	}
	// Get clients for all clusters
	clients, err := kubeutils.GetClients(options.KubeconfigFilename, options.KubeContexts)
	if err != nil {
		return err
	}

	lbs, err := gcplb.NewLoadBalancerSyncer(options.LBName, clients, cloudInterface, options.GCPProject)
	if err != nil {
		return err
	}
	if delErr := lbs.RemoveFromClusters(&ing, clients, options.ForceUpdate); delErr != nil {
		err = multierror.Append(err, delErr)
	}

	// Delete ingress resource from clusters
	is := ingress.NewIngressSyncer()
	if is == nil {
		err = multierror.Append(err, fmt.Errorf("unexpected ingress syncer is nil"))
		// No point in proceeding.
		return err
	}
	isErr := is.DeleteIngress(&ing, clients)
	if isErr != nil {
		err = multierror.Append(err, isErr)
	}
	return err
}
<commit_msg>Delete ingress from cluster when updating GCP resources failed only if force=true<commit_after>// Copyright 2018 Google, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"fmt"
	"io"

	multierror "github.com/hashicorp/go-multierror"
	"github.com/spf13/cobra"
	"k8s.io/api/extensions/v1beta1"
	// gcp is needed for GKE cluster auth to work.
	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"

	"github.com/GoogleCloudPlatform/k8s-multicluster-ingress/app/kubemci/pkg/gcp/cloudinterface"
	gcplb "github.com/GoogleCloudPlatform/k8s-multicluster-ingress/app/kubemci/pkg/gcp/loadbalancer"
	gcputils "github.com/GoogleCloudPlatform/k8s-multicluster-ingress/app/kubemci/pkg/gcp/utils"
	"github.com/GoogleCloudPlatform/k8s-multicluster-ingress/app/kubemci/pkg/ingress"
	"github.com/GoogleCloudPlatform/k8s-multicluster-ingress/app/kubemci/pkg/kubeutils"
)

var (
	removeClustersShortDesc = "Remove an existing multicluster ingress from some clusters."
	removeClustersLongDesc  = `Remove an existing multicluster ingress from some clusters.

	Takes a load balancer name and a list of clusters and removes the existing multicluster ingress from those clusters.
	If the clusters have already been deleted, you can run "kubemci create --force" with the updated cluster list to update the
	load balancer to be restricted to those clusters. That will however not delete the ingress from old clusters (which is fine
	if the clusters have been deleted already).
`
)

type removeClustersOptions struct {
	// Name of the YAML file containing ingress spec.
	// Required.
	IngressFilename string
	// Path to kubeconfig file.
	// Required.
	KubeconfigFilename string
	// Names of the contexts to use from the kubeconfig file.
	KubeContexts []string
	// Name of the load balancer.
	// Required.
	LBName string
	// Name of the GCP project in which the load balancer is configured.
	GCPProject string
	// Overwrite values when they differ from what's requested. If
	// the resource does not exist, or is already the correct
	// value, then 'force' is a no-op.
	ForceUpdate bool
	// Name of the namespace for the ingress when none is provided (mismatch of option with spec causes an error).
	Namespace string
}

func newCmdRemoveClusters(out, err io.Writer) *cobra.Command {
	var options removeClustersOptions
	cmd := &cobra.Command{
		Use:   "remove-clusters",
		Short: removeClustersShortDesc,
		Long:  removeClustersLongDesc,
		Run: func(cmd *cobra.Command, args []string) {
			if err := validateRemoveClustersArgs(&options, args); err != nil {
				fmt.Println(err)
				return
			}
			if err := runRemoveClusters(&options, args); err != nil {
				fmt.Println("Error removing clusters:", err)
				return
			}
		},
	}
	addRemoveClustersFlags(cmd, &options)
	return cmd
}

func addRemoveClustersFlags(cmd *cobra.Command, options *removeClustersOptions) error {
	cmd.Flags().StringVarP(&options.IngressFilename, "ingress", "i", options.IngressFilename, "[required] filename containing ingress spec")
	cmd.Flags().StringVarP(&options.KubeconfigFilename, "kubeconfig", "k", options.KubeconfigFilename, "[required] path to kubeconfig file")
	cmd.Flags().StringSliceVar(&options.KubeContexts, "kubecontexts", options.KubeContexts, "[optional] contexts in the kubeconfig file to remove the ingress from")
	cmd.Flags().StringVarP(&options.GCPProject, "gcp-project", "", options.GCPProject, "[required] name of the gcp project")
	cmd.Flags().BoolVarP(&options.ForceUpdate, "force", "f", options.ForceUpdate, "[optional] overwrite existing settings if they are different")
	cmd.Flags().StringVarP(&options.Namespace, "namespace", "n", options.Namespace, "[optional] namespace for the ingress only if left unspecified by ingress spec")
	return nil
}

func validateRemoveClustersArgs(options *removeClustersOptions, args []string) error {
	if len(args) != 1 {
		return fmt.Errorf("unexpected args: %v. Expected one arg as name of load balancer", args)
	}
	// Verify that the required options are not missing.
	if options.IngressFilename == "" {
		return fmt.Errorf("unexpected missing argument ingress")
	}
	if options.GCPProject == "" {
		project, err := gcputils.GetProjectFromGCloud()
		if project == "" || err != nil {
			return fmt.Errorf("unexpected cannot determine GCP project. Either set --gcp-project flag, or set a default project with gcloud such that gcloud config get-value project returns that")
		}
		options.GCPProject = project
	}
	if options.KubeconfigFilename == "" {
		return fmt.Errorf("unexpected missing argument kubeconfig")
	}
	return nil
}

// runRemoveClusters removes the given load balancer from the given list of clusters.
func runRemoveClusters(options *removeClustersOptions, args []string) error {
	options.LBName = args[0]

	// Unmarshal the YAML into ingress struct.
	var ing v1beta1.Ingress
	if err := ingress.UnmarshallAndApplyDefaults(options.IngressFilename, options.Namespace, &ing); err != nil {
		return fmt.Errorf("error in unmarshalling the yaml file %s, err: %s", options.IngressFilename, err)
	}
	cloudInterface, err := cloudinterface.NewGCECloudInterface(options.GCPProject)
	if err != nil {
		err := fmt.Errorf("error in creating cloud interface: %s", err)
		fmt.Println(err)
		return err
	}
	// Get clients for all clusters
	clients, err := kubeutils.GetClients(options.KubeconfigFilename, options.KubeContexts)
	if err != nil {
		return err
	}

	lbs, err := gcplb.NewLoadBalancerSyncer(options.LBName, clients, cloudInterface, options.GCPProject)
	if err != nil {
		return err
	}
	if delErr := lbs.RemoveFromClusters(&ing, clients, options.ForceUpdate); delErr != nil {
		if !options.ForceUpdate {
			return delErr
		}
		fmt.Printf("%s. Continuing with force remove\n", delErr)
		err = multierror.Append(err, delErr)
	}

	// Delete ingress resource from clusters
	is := ingress.NewIngressSyncer()
	if is == nil {
		err = multierror.Append(err, fmt.Errorf("unexpected ingress syncer is nil"))
		// No point in proceeding.
		return err
	}
	isErr := is.DeleteIngress(&ing, clients)
	if isErr != nil {
		err = multierror.Append(err, isErr)
	}
	return err
}
<|endoftext|>


<commit_before>// +build never

/*
Copyright 2016 The Camlistore 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 (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"go/format"
	"io"
	"log"
	"os"
	"os/exec"
)

type matcher func([]byte) bool

// processDoc runs "go doc" for the given type name,
// filtering the output by deleting lines matching any of the deleters,
// and writes the rest of the output to w.
func processDoc(w io.Writer, name string, deleters ...matcher) error {
	var buf, errBuf bytes.Buffer
	cmd := exec.Command("go", "doc", name)
	cmd.Stdout = &buf
	cmd.Stderr = &errBuf
	if err := cmd.Run(); err != nil {
		return fmt.Errorf("go doc %s error: %v, %s", name, err, errBuf.Bytes())
	}
	scanner := bufio.NewScanner(bytes.NewReader(buf.Bytes()))
NextLine:
	for scanner.Scan() {
		line := scanner.Bytes()
		for _, d := range deleters {
			if d(line) {
				continue NextLine
			}
		}
		var err error
		if _, err = w.Write(line); err == nil {
			_, err = w.Write([]byte{'\n'})
		}
		if err != nil {
			return err
		}
	}
	return scanner.Err()
}

func main() {
	var buf bytes.Buffer

	buf.WriteString(`// generated by gensearchtypes.go; DO NOT EDIT

/*
Copyright 2016 The Camlistore 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 (
    "net/url"
    "time"

    "camlistore.org/pkg/blob"
    "camlistore.org/pkg/types/camtypes"
)

// Duplicating the search pkg types in here - since we only use them for json
// decoding - , instead of importing them through the search package, which would
// bring in more dependencies, and hence a larger js file.
// To give an idea, the generated publisher.js is ~3.5MB, whereas if we instead import
// camlistore.org/pkg/search to use its types instead of the ones below, we grow to
// ~5.7MB.

`)

	P := func(name string, deleters ...matcher) {
		if err := processDoc(&buf, "camlistore.org/pkg/search."+name, deleters...); err != nil {
			log.Fatal(err)
		}
	}

	matchFuncOrDocText := func(line []byte) bool {
		return bytes.HasPrefix(line, []byte("func")) || bytes.HasPrefix(line, []byte("    "))
	}
	matchDescribeRequest := func(line []byte) bool {
		return bytes.HasPrefix(line, []byte("\tRequest *DescribeRequest"))
	}

	for _, task := range []struct {
		Name  string
		Extra []matcher
	}{
		{"SearchResult", nil},
		{"SearchResultBlob", nil},
		{"DescribeResponse", nil},
		{"MetaMap", nil},

		// stripping DescribeRequest from DescribeBlob because it would pull a lot more of search pkg in
		{"DescribedBlob", []matcher{matchDescribeRequest}},

		{"DescribedPermanode", nil},
	} {
		P(task.Name,
			append([]matcher{matchFuncOrDocText}, task.Extra...)...)
	}

	src, err := format.Source(buf.Bytes())
	if err != nil {
		log.Fatalf("formatting: %v\n%s", err, buf.String())
	}

	flagOut := flag.String("out", "zsearch.go", "output file name (empty or '-' is stdout)")
	flag.Parse()

	out := os.Stdout
	if *flagOut != "" && *flagOut != "-" {
		if out, err = os.Create(*flagOut); err != nil {
			log.Fatal(err)
		}
		defer func() {
			if err := out.Close(); err != nil {
				log.Fatal(err)
			}
		}()
	}
	if _, err := out.Write(src); err != nil {
		log.Fatal(err)
	}
}
<commit_msg>app/publisher: rewrite gensearchtypes.go using go/ast<commit_after>// +build ignore

/*
Copyright 2016 The Camlistore Authors.

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

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

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

package main

import (
	"flag"
	"fmt"
	"go/ast"
	"go/build"
	"go/format"
	"go/parser"
	"go/token"
	"log"
	"os"
)

func main() {
	flagOut := flag.String("out", "zsearch.go", "output file name ('-' is stdout)")
	flag.Parse()

	out := os.Stdout
	if *flagOut != "-" {
		var err error
		if out, err = os.Create(*flagOut); err != nil {
			log.Fatal(err)
		}
		defer func() {
			if err := out.Close(); err != nil {
				log.Fatal(err)
			}
		}()
	}

	fmt.Fprintln(out, `// generated by gensearchtypes.go; DO NOT EDIT

/*
Copyright 2016 The Camlistore 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 (
	"net/url"
	"time"

	"camlistore.org/pkg/blob"
	"camlistore.org/pkg/types/camtypes"
)

// Duplicating the search pkg types in here - since we only use them for json
// decoding - , instead of importing them through the search package, which would
// bring in more dependencies, and hence a larger js file.
// To give an idea, the generated publisher.js is ~3.5MB, whereas if we instead import
// camlistore.org/pkg/search to use its types instead of the ones below, we grow to
// ~5.7MB.`)

	wantTypes := []string{
		"SearchResult",
		"SearchResultBlob",
		"DescribeResponse",
		"MetaMap",
		"DescribedBlob",
		"DescribedPermanode",
	}

	m := make(map[string]*ast.GenDecl, len(wantTypes))
	for _, n := range wantTypes {
		m[n] = nil
	}

	fileSet, pkg, err := loadPkg("camlistore.org/pkg/search")
	if err != nil {
		log.Fatal(err)
	}

	merged := ast.MergePackageFiles(pkg, 0)

	for _, decl := range merged.Decls {
		g, ok := decl.(*ast.GenDecl)
		if !ok || g.Tok != token.TYPE || len(g.Specs) != 1 {
			// skip non-type declarations and
			// combined type declarations in the form:
			//  type (X T1; Y T2...)
			continue
		}

		t := g.Specs[0].(*ast.TypeSpec)
		if _, ok := m[t.Name.Name]; ok {
			m[t.Name.Name] = g
		}
	}

	for _, n := range wantTypes {
		g := m[n]
		if g == nil {
			log.Fatalf("type %v not found", n)
		}

		// strip DescribeRequest from DescribeBlob because it would pull a lot more of search pkg in
		t := g.Specs[0].(*ast.TypeSpec)
		if t.Name.Name == "DescribedBlob" {
			fl := t.Type.(*ast.StructType).Fields
			var nfl []*ast.Field
			for _, f := range fl.List {
				if isStarExprName(f.Type, "DescribeRequest") {
					continue
				}
				nfl = append(nfl, f)
			}
			fl.List = nfl
		}

		fmt.Fprintln(out)
		format.Node(out, fileSet, g)
		fmt.Fprintln(out)
	}
}

func isStarExprName(x ast.Expr, name string) bool {
	star, ok := x.(*ast.StarExpr)
	if !ok {
		return false
	}

	id, ok := star.X.(*ast.Ident)
	if !ok {
		return false
	}

	return id.Name == name
}

func loadPkg(importPath string) (*token.FileSet, *ast.Package, error) {
	buildPkg, err := build.Import(importPath, ".", 0)
	if err != nil {
		return nil, nil, err
	}

	fileSet := token.NewFileSet()
	pkgs, err := parser.ParseDir(fileSet, buildPkg.Dir, nil, parser.ParseComments)
	if err != nil {
		return nil, nil, err
	}

	pkg := pkgs[buildPkg.Name]
	if pkg == nil {
		return nil, nil, fmt.Errorf("package %v not found in %v", buildPkg.Name, importPath)
	}

	ast.PackageExports(pkg)
	return fileSet, pkg, nil
}
<|endoftext|>


<commit_before>package pay

import (
	"github.com/silenceper/wechat/v2/pay/config"
	"github.com/silenceper/wechat/v2/pay/notify"
	"github.com/silenceper/wechat/v2/pay/order"
)

//Pay 微信支付相关API
type Pay struct {
	cfg *config.Config
}

//NewPay 实例化微信支付相关API
func NewPay(cfg *config.Config) *Pay {
	return &Pay{cfg}
}

// GetOrder  下单
func (pay *Pay) GetOrder() *order.Order {
	return order.NewOrder(pay.cfg)
}

// GetNotify  通知
func (pay *Pay) GetNotify() *notify.Notify {
	return notify.NewNotify(pay.cfg)
}
<commit_msg>add GetRefund (#286)<commit_after>package pay

import (
	"github.com/silenceper/wechat/v2/pay/config"
	"github.com/silenceper/wechat/v2/pay/notify"
	"github.com/silenceper/wechat/v2/pay/order"
	"github.com/silenceper/wechat/v2/pay/refund"
)

//Pay 微信支付相关API
type Pay struct {
	cfg *config.Config
}

//NewPay 实例化微信支付相关API
func NewPay(cfg *config.Config) *Pay {
	return &Pay{cfg}
}

// GetOrder  下单
func (pay *Pay) GetOrder() *order.Order {
	return order.NewOrder(pay.cfg)
}

// GetNotify  通知
func (pay *Pay) GetNotify() *notify.Notify {
	return notify.NewNotify(pay.cfg)
}

// GetRefund  退款
func (pay *Pay) GetRefund() *refund.Refund {
	return refund.NewRefund(pay.cfg)
}
<|endoftext|>


<commit_before>package peco

import (
	"errors"
	"fmt"
	"os"
	"runtime"
	"sync"
	"time"

	"github.com/nsf/termbox-go"
)

type PecoOptions struct {
	OptTTY            string `long:"tty" description:"path to the TTY (usually, the value of $TTY)"`
	OptQuery          string `long:"query" description:"initial value for query"`
	OptRcfile         string `long:"rcfile" description:"path to the settings file"`
	OptNoIgnoreCase   bool   `long:"no-ignore-case" description:"start in case-sensitive-mode (DEPRECATED)" default:"false"`
	OptBufferSize     int    `long:"buffer-size" short:"b" description:"number of lines to keep in search buffer"`
	OptEnableNullSep  bool   `long:"null" description:"expect NUL (\\0) as separator for target/output"`
	OptInitialIndex   int    `long:"initial-index" description:"position of the initial index of the selection (0 base)"`
	OptInitialMatcher string `long:"initial-matcher" description:"specify the default matcher"`
	OptPrompt         string `long:"prompt" description:"specify the prompt string"`
	OptLayout         string `long:"layout" description:"layout to be used 'top-down' (default) or 'bottom-up'"`
}

func NewPecoOption() *PecoOptions {
	return &PecoOptions{}
}

// BufferSize returns the specified buffer size. Fulfills CtxOptions
func (o PecoOptions) BufferSize() int {
	return o.OptBufferSize
}

// EnableNullSep returns tru if --null was specified. Fulfills CtxOptions
func (o PecoOptions) EnableNullSep() bool {
	return o.OptEnableNullSep
}

func (o PecoOptions) InitialIndex() int {
	if o.OptInitialIndex >= 0 {
		return o.OptInitialIndex + 1
	}
	return 1
}

func (o PecoOptions) LayoutType() string {
	return o.OptLayout
}

type ChoicesHelper struct {
	*Ctx
}

func (i *ChoicesHelper) draw(choices []Line) {
	m := &sync.Mutex{}
	var refresh *time.Timer

	i.lines = choices
	m.Lock()
	if refresh == nil {
		refresh = time.AfterFunc(100*time.Millisecond, func() {
			if !i.ExecQuery() {
				i.DrawMatches(i.lines)
			}
			m.Lock()
			refresh = nil
			m.Unlock()
		})
	}
	m.Unlock()
}

type Choosable interface {
	Choice() string
	Value() string
}

type Choice struct {
	C string
	V string
}

func (c *Choice) Choice() string {
	return c.C
}

func (c *Choice) Value() string {
	return c.V
}

// Custom implements Choosalbe interface.
func Choose(itemName, message string, choices []Choosable) ([]Choosable, error) {
	if len(choices) == 0 {
		err := fmt.Errorf("there is no %s.", itemName)
		return nil, err
	}

	pecoOpt := &PecoOptions{
		OptPrompt: fmt.Sprintf("%s >", message),
	}

	result, err := PecolibWithOptions(choices, pecoOpt)
	if err != nil || len(result) == 0 {
		err := fmt.Errorf("no select %s.", itemName)
		return nil, err
	}

	chosen := make([]Choosable, 0, len(result))
	for _, r := range result {
		if c, ok := r.(Choosable); ok {
			chosen = append(chosen, c)
		}
	}

	return chosen, nil
}

func Pecolib(choices []Choosable) ([]interface{}, error) {
	return pecolibWrap(choices, &PecoOptions{})
}

func PecolibWithPrompt(choices []Choosable, prompt string) ([]interface{}, error) {
	return pecolibWrap(choices, &PecoOptions{OptPrompt: prompt})
}

func PecolibWithOptions(choices []Choosable, opts *PecoOptions) ([]interface{}, error) {
	return pecolibWrap(choices, opts)
}

func pecolibWrap(choices []Choosable, opts *PecoOptions) ([]interface{}, error) {
	if choices == nil {
		return nil, errors.New("choices is nil.")
	}
	if len(choices) == 0 {
		return nil, errors.New("choices is empty.")
	}

	choiceMap := make(map[string]interface{})
	matches := make([]Line, 0, len(choices))
	for _, c := range choices {
		if c == nil {
			continue
		}
		s := c.Choice()
		choiceMap[s] = c

		// TODO investigate NewNoMatch boolean
		matches = append(matches, NewRawLine(s, true))
	}

	if len(matches) == 0 {
		return nil, errors.New("choices are all nil.")
	}

	matched, err := pecolib(matches, opts)
	if err != nil {
		return nil, err
	}

	ret := make([]interface{}, 0, len(matched))
	for _, m := range matched {
		s := m.Output()
		if v, ok := choiceMap[s]; ok {
			ret = append(ret, v)
		} else {
			return nil, errors.New("internal error")
		}
	}

	return ret, nil
}

func pecolib(choices []Line, opts *PecoOptions) ([]Line, error) {
	var err error
	var out []Line

	if envvar := os.Getenv("GOMAXPROCS"); envvar == "" {
		runtime.GOMAXPROCS(runtime.NumCPU())
	}

	if opts.OptLayout != "" {
		if !IsValidLayoutType(LayoutType(opts.OptLayout)) {
			return nil, errors.New(fmt.Sprintf("Unknown layout: '%s'\n", opts.OptLayout))
		}
	}

	ctx := NewCtx(opts)
	defer func() {
		if err := recover(); err != nil {
			fmt.Printf("Error in recover.")
			return
		}
	}()

	if opts.OptRcfile == "" {
		file, err := LocateRcfile()
		if err == nil {
			opts.OptRcfile = file
		}
	}

	if opts.OptRcfile != "" {
		err = ctx.ReadConfig(opts.OptRcfile)
		if err != nil {
			return nil, err
		}
	}

	if len(opts.OptPrompt) > 0 {
		ctx.SetPrompt(opts.OptPrompt)
	}

	choicesHelper := ChoicesHelper{ctx}
	choicesHelper.draw(choices)
	err = TtyReady()
	if err != nil {
		return nil, err
	}
	defer TtyTerm()

	err = termbox.Init()
	if err != nil {
		return nil, err
	}
	defer termbox.Close()

	// Windows handle Esc/Alt self
	if runtime.GOOS == "windows" {
		termbox.SetInputMode(termbox.InputEsc | termbox.InputAlt)
	}

	view := ctx.NewView()
	filter := ctx.NewFilter()
	input := ctx.NewInput()
	sig := ctx.NewSignalHandler()

	loopers := []interface {
		Loop()
	}{
		view,
		filter,
		input,
		sig,
	}
	for _, looper := range loopers {
		ctx.AddWaitGroup(1)
		go looper.Loop()
	}

	if len(opts.OptQuery) > 0 {
		ctx.SetQuery([]rune(opts.OptQuery))
		ctx.ExecQuery()
	} else {
		view.Refresh()
	}

	ctx.WaitDone()

	st := ctx.ExitStatus()
	if st != 0 {
		return nil, errors.New(fmt.Sprintf("something error code: %d", st))
	}

	resultCh := ctx.ResultCh()
	if resultCh == nil {
		return []Line{}, nil
	}

	for match := range resultCh {
		out = append(out, match)
	}

	return out, err
}
<commit_msg>added default query to choose()<commit_after>package peco

import (
	"errors"
	"fmt"
	"os"
	"runtime"
	"sync"
	"time"

	"github.com/nsf/termbox-go"
)

type PecoOptions struct {
	OptTTY            string `long:"tty" description:"path to the TTY (usually, the value of $TTY)"`
	OptQuery          string `long:"query" description:"initial value for query"`
	OptRcfile         string `long:"rcfile" description:"path to the settings file"`
	OptNoIgnoreCase   bool   `long:"no-ignore-case" description:"start in case-sensitive-mode (DEPRECATED)" default:"false"`
	OptBufferSize     int    `long:"buffer-size" short:"b" description:"number of lines to keep in search buffer"`
	OptEnableNullSep  bool   `long:"null" description:"expect NUL (\\0) as separator for target/output"`
	OptInitialIndex   int    `long:"initial-index" description:"position of the initial index of the selection (0 base)"`
	OptInitialMatcher string `long:"initial-matcher" description:"specify the default matcher"`
	OptPrompt         string `long:"prompt" description:"specify the prompt string"`
	OptLayout         string `long:"layout" description:"layout to be used 'top-down' (default) or 'bottom-up'"`
}

func NewPecoOption() *PecoOptions {
	return &PecoOptions{}
}

// BufferSize returns the specified buffer size. Fulfills CtxOptions
func (o PecoOptions) BufferSize() int {
	return o.OptBufferSize
}

// EnableNullSep returns tru if --null was specified. Fulfills CtxOptions
func (o PecoOptions) EnableNullSep() bool {
	return o.OptEnableNullSep
}

func (o PecoOptions) InitialIndex() int {
	if o.OptInitialIndex >= 0 {
		return o.OptInitialIndex + 1
	}
	return 1
}

func (o PecoOptions) LayoutType() string {
	return o.OptLayout
}

type ChoicesHelper struct {
	*Ctx
}

func (i *ChoicesHelper) draw(choices []Line) {
	m := &sync.Mutex{}
	var refresh *time.Timer

	i.lines = choices
	m.Lock()
	if refresh == nil {
		refresh = time.AfterFunc(100*time.Millisecond, func() {
			if !i.ExecQuery() {
				i.DrawMatches(i.lines)
			}
			m.Lock()
			refresh = nil
			m.Unlock()
		})
	}
	m.Unlock()
}

type Choosable interface {
	Choice() string
	Value() string
}

type Choice struct {
	C string
	V string
}

func (c *Choice) Choice() string {
	return c.C
}

func (c *Choice) Value() string {
	return c.V
}

// Custom implements Choosalbe interface.
func Choose(itemName, message, defaultQuery string, choices []Choosable) ([]Choosable, error) {
	if len(choices) == 0 {
		err := fmt.Errorf("there is no %s.", itemName)
		return nil, err
	}

	pecoOpt := &PecoOptions{
		OptPrompt: fmt.Sprintf("%s >", message),
	}

	if defaultQuery != "" {
		pecoOpt.OptQuery = defaultQuery
	}

	result, err := PecolibWithOptions(choices, pecoOpt)
	if err != nil || len(result) == 0 {
		err := fmt.Errorf("no select %s.", itemName)
		return nil, err
	}

	chosen := make([]Choosable, 0, len(result))
	for _, r := range result {
		if c, ok := r.(Choosable); ok {
			chosen = append(chosen, c)
		}
	}

	return chosen, nil
}

func Pecolib(choices []Choosable) ([]interface{}, error) {
	return pecolibWrap(choices, &PecoOptions{})
}

func PecolibWithPrompt(choices []Choosable, prompt string) ([]interface{}, error) {
	return pecolibWrap(choices, &PecoOptions{OptPrompt: prompt})
}

func PecolibWithOptions(choices []Choosable, opts *PecoOptions) ([]interface{}, error) {
	return pecolibWrap(choices, opts)
}

func pecolibWrap(choices []Choosable, opts *PecoOptions) ([]interface{}, error) {
	if choices == nil {
		return nil, errors.New("choices is nil.")
	}
	if len(choices) == 0 {
		return nil, errors.New("choices is empty.")
	}

	choiceMap := make(map[string]interface{})
	matches := make([]Line, 0, len(choices))
	for _, c := range choices {
		if c == nil {
			continue
		}
		s := c.Choice()
		choiceMap[s] = c

		// TODO investigate NewNoMatch boolean
		matches = append(matches, NewRawLine(s, true))
	}

	if len(matches) == 0 {
		return nil, errors.New("choices are all nil.")
	}

	matched, err := pecolib(matches, opts)
	if err != nil {
		return nil, err
	}

	ret := make([]interface{}, 0, len(matched))
	for _, m := range matched {
		s := m.Output()
		if v, ok := choiceMap[s]; ok {
			ret = append(ret, v)
		} else {
			return nil, errors.New("internal error")
		}
	}

	return ret, nil
}

func pecolib(choices []Line, opts *PecoOptions) ([]Line, error) {
	var err error
	var out []Line

	if envvar := os.Getenv("GOMAXPROCS"); envvar == "" {
		runtime.GOMAXPROCS(runtime.NumCPU())
	}

	if opts.OptLayout != "" {
		if !IsValidLayoutType(LayoutType(opts.OptLayout)) {
			return nil, errors.New(fmt.Sprintf("Unknown layout: '%s'\n", opts.OptLayout))
		}
	}

	ctx := NewCtx(opts)
	defer func() {
		if err := recover(); err != nil {
			fmt.Printf("Error in recover.")
			return
		}
	}()

	if opts.OptRcfile == "" {
		file, err := LocateRcfile()
		if err == nil {
			opts.OptRcfile = file
		}
	}

	if opts.OptRcfile != "" {
		err = ctx.ReadConfig(opts.OptRcfile)
		if err != nil {
			return nil, err
		}
	}

	if len(opts.OptPrompt) > 0 {
		ctx.SetPrompt(opts.OptPrompt)
	}

	choicesHelper := ChoicesHelper{ctx}
	choicesHelper.draw(choices)
	err = TtyReady()
	if err != nil {
		return nil, err
	}
	defer TtyTerm()

	err = termbox.Init()
	if err != nil {
		return nil, err
	}
	defer termbox.Close()

	// Windows handle Esc/Alt self
	if runtime.GOOS == "windows" {
		termbox.SetInputMode(termbox.InputEsc | termbox.InputAlt)
	}

	view := ctx.NewView()
	filter := ctx.NewFilter()
	input := ctx.NewInput()
	sig := ctx.NewSignalHandler()

	loopers := []interface {
		Loop()
	}{
		view,
		filter,
		input,
		sig,
	}
	for _, looper := range loopers {
		ctx.AddWaitGroup(1)
		go looper.Loop()
	}

	if len(opts.OptQuery) > 0 {
		ctx.SetQuery([]rune(opts.OptQuery))
		ctx.ExecQuery()
	} else {
		view.Refresh()
	}

	ctx.WaitDone()

	st := ctx.ExitStatus()
	if st != 0 {
		return nil, errors.New(fmt.Sprintf("something error code: %d", st))
	}

	resultCh := ctx.ResultCh()
	if resultCh == nil {
		return []Line{}, nil
	}

	for match := range resultCh {
		out = append(out, match)
	}

	return out, err
}
<|endoftext|>


<commit_before>package organizations

import (
	"fmt"
	"io"
	"strconv"
	"time"
)

type CreateOrganizationRequest struct {
	Name string `json:"name"`
}

type Organization struct {
	ID        string               `json:"id"`
	CreatedAt time.Time            `json:"created_at"`
	UpdatedAt time.Time            `json:"updated_at"`
	DeletedAt *time.Time           `json:"deleted_at"`
	Name      string               `json:"name"`
	Members   []OrganizationMember `json:"members"`
}

type OrganizationMember struct {
	ID        string           `json:"id"`
	UserID    string           `json:"user_id"`
	Username  string           `json:"username"`
	RoleID    string           `json:"role_id"`
	Role      OrganizationRole `json:"role"`
	CreatedAt time.Time        `json:"created_at"`
	DeletedAt *time.Time       `json:"deleted_at"`
}

type OrganizationMemberUpdate struct {
	UserID    string     `json:"user_id"`
	RoleID    *string    `json:"role_id"`
	DeletedAt *time.Time `json:"deleted_at"`
}

type UpdateOrganizationMembersInput struct {
	OrgID   string                     `json:"org_id"`
	Members []OrganizationMemberUpdate `json:"members"`
}

type UserOrganizationRole struct {
	RoleID       string           `json:"role_id"`
	Role         OrganizationRole `json:"role"`
	Organization Organization     `json:"organization"`
}

type OrganizationRole string

const (
	OrganizationRoleOwner   OrganizationRole = "Owner"
	OrganizationRoleManager OrganizationRole = "Manager"
	OrganizationRoleMember  OrganizationRole = "Member"
)

var AllOrganizationRole = []OrganizationRole{
	OrganizationRoleOwner,
	OrganizationRoleManager,
	OrganizationRoleMember,
}

func (e OrganizationRole) IsValid() bool {
	switch e {
	case OrganizationRoleOwner, OrganizationRoleManager, OrganizationRoleMember:
		return true
	}
	return false
}

func (e OrganizationRole) String() string {
	return string(e)
}

func (e *OrganizationRole) UnmarshalGQL(v interface{}) error {
	str, ok := v.(string)
	if !ok {
		return fmt.Errorf("enums must be strings")
	}

	*e = OrganizationRole(str)
	if !e.IsValid() {
		return fmt.Errorf("%s is not a valid OrganizationRole", str)
	}
	return nil
}

func (e OrganizationRole) MarshalGQL(w io.Writer) {
	fmt.Fprint(w, strconv.Quote(e.String()))
}

type Permission string

const (
	// Grants all permissions over all objects in the system.
	// Reserved for System Admin role. Cannot be granted to or inherited by other roles.
	PermissionAllPermissions Permission = "ALL_PERMISSIONS"
	// Grants the ability to modify an organization's settings, including billing information.
	PermissionOrganizationModify Permission = "ORGANIZATION_MODIFY"
	// Grants the ability to view basic information about an organization, including its name,
	// the date and time it was created, etc.
	PermissionOrganizationView Permission = "ORGANIZATION_VIEW"
	// Grants the ability to invite users to an organization.
	PermissionOrganizationUserCreate Permission = "ORGANIZATION_USER_CREATE"
	// Grants the ability to change the roles of existing users within an organization.
	PermissionOrganizationUserModify Permission = "ORGANIZATION_USER_MODIFY"
	// Grants the ability to remove users from an organization.
	PermissionOrganizationUserRemove Permission = "ORGANIZATION_USER_REMOVE"
	// Grants the ability to view a list of all the organization's members.
	PermissionOrganizationUserView Permission = "ORGANIZATION_USER_VIEW"
	// Grants the ability to create a new software list and add it to an organization's software inventory.
	PermissionOrganizationSoftwareListCreate Permission = "ORGANIZATION_SOFTWARE_LIST_CREATE"
	// Grants the ability to modify an organization's existing software lists,
	// including adding, modifying, and removing components from individual software lists.
	PermissionOrganizationSoftwareListModify Permission = "ORGANIZATION_SOFTWARE_LIST_MODIFY"
	// Grants the ability to view an organization's software lists and any components they contain.
	// This also includes the ability to export an SBOM for the software lists and view risk scoring data.
	PermissionOrganizationSoftwareListView Permission = "ORGANIZATION_SOFTWARE_LIST_VIEW"
	// Grants the ability to remove software lists from an organization's software inventory.
	PermissionOrganizationSoftwareListRemove Permission = "ORGANIZATION_SOFTWARE_LIST_REMOVE"
)

var AllPermission = []Permission{
	PermissionAllPermissions,
	PermissionOrganizationModify,
	PermissionOrganizationView,
	PermissionOrganizationUserCreate,
	PermissionOrganizationUserModify,
	PermissionOrganizationUserRemove,
	PermissionOrganizationUserView,
	PermissionOrganizationSoftwareListCreate,
	PermissionOrganizationSoftwareListModify,
	PermissionOrganizationSoftwareListView,
	PermissionOrganizationSoftwareListRemove,
}

func (e Permission) IsValid() bool {
	switch e {
	case PermissionAllPermissions, PermissionOrganizationModify, PermissionOrganizationView, PermissionOrganizationUserCreate, PermissionOrganizationUserModify, PermissionOrganizationUserRemove, PermissionOrganizationUserView, PermissionOrganizationSoftwareListCreate, PermissionOrganizationSoftwareListModify, PermissionOrganizationSoftwareListView, PermissionOrganizationSoftwareListRemove:
		return true
	}
	return false
}

func (e Permission) String() string {
	return string(e)
}

func (e *Permission) UnmarshalGQL(v interface{}) error {
	str, ok := v.(string)
	if !ok {
		return fmt.Errorf("enums must be strings")
	}

	*e = Permission(str)
	if !e.IsValid() {
		return fmt.Errorf("%s is not a valid Permission", str)
	}
	return nil
}

func (e Permission) MarshalGQL(w io.Writer) {
	fmt.Fprint(w, strconv.Quote(e.String()))
}
<commit_msg>Adding joined at<commit_after>package organizations

import (
	"fmt"
	"io"
	"strconv"
	"time"
)

type CreateOrganizationRequest struct {
	Name string `json:"name"`
}

type Organization struct {
	ID        string               `json:"id"`
	CreatedAt time.Time            `json:"created_at"`
	UpdatedAt time.Time            `json:"updated_at"`
	DeletedAt *time.Time           `json:"deleted_at"`
	Name      string               `json:"name"`
	Members   []OrganizationMember `json:"members"`
}

type OrganizationMember struct {
	ID        string           `json:"id"`
	UserID    string           `json:"user_id"`
	Username  string           `json:"username"`
	RoleID    string           `json:"role_id"`
	Role      OrganizationRole `json:"role"`
	CreatedAt time.Time        `json:"created_at"`
	JoinedAt  time.Time        `json:"joined_at"`
	DeletedAt *time.Time       `json:"deleted_at"`
}

type OrganizationMemberUpdate struct {
	UserID    string     `json:"user_id"`
	RoleID    *string    `json:"role_id"`
	DeletedAt *time.Time `json:"deleted_at"`
}

type UpdateOrganizationMembersInput struct {
	OrgID   string                     `json:"org_id"`
	Members []OrganizationMemberUpdate `json:"members"`
}

type UserOrganizationRole struct {
	RoleID       string           `json:"role_id"`
	Role         OrganizationRole `json:"role"`
	Organization Organization     `json:"organization"`
}

type OrganizationRole string

const (
	OrganizationRoleOwner   OrganizationRole = "Owner"
	OrganizationRoleManager OrganizationRole = "Manager"
	OrganizationRoleMember  OrganizationRole = "Member"
)

var AllOrganizationRole = []OrganizationRole{
	OrganizationRoleOwner,
	OrganizationRoleManager,
	OrganizationRoleMember,
}

func (e OrganizationRole) IsValid() bool {
	switch e {
	case OrganizationRoleOwner, OrganizationRoleManager, OrganizationRoleMember:
		return true
	}
	return false
}

func (e OrganizationRole) String() string {
	return string(e)
}

func (e *OrganizationRole) UnmarshalGQL(v interface{}) error {
	str, ok := v.(string)
	if !ok {
		return fmt.Errorf("enums must be strings")
	}

	*e = OrganizationRole(str)
	if !e.IsValid() {
		return fmt.Errorf("%s is not a valid OrganizationRole", str)
	}
	return nil
}

func (e OrganizationRole) MarshalGQL(w io.Writer) {
	fmt.Fprint(w, strconv.Quote(e.String()))
}

type Permission string

const (
	// Grants all permissions over all objects in the system.
	// Reserved for System Admin role. Cannot be granted to or inherited by other roles.
	PermissionAllPermissions Permission = "ALL_PERMISSIONS"
	// Grants the ability to modify an organization's settings, including billing information.
	PermissionOrganizationModify Permission = "ORGANIZATION_MODIFY"
	// Grants the ability to view basic information about an organization, including its name,
	// the date and time it was created, etc.
	PermissionOrganizationView Permission = "ORGANIZATION_VIEW"
	// Grants the ability to invite users to an organization.
	PermissionOrganizationUserCreate Permission = "ORGANIZATION_USER_CREATE"
	// Grants the ability to change the roles of existing users within an organization.
	PermissionOrganizationUserModify Permission = "ORGANIZATION_USER_MODIFY"
	// Grants the ability to remove users from an organization.
	PermissionOrganizationUserRemove Permission = "ORGANIZATION_USER_REMOVE"
	// Grants the ability to view a list of all the organization's members.
	PermissionOrganizationUserView Permission = "ORGANIZATION_USER_VIEW"
	// Grants the ability to create a new software list and add it to an organization's software inventory.
	PermissionOrganizationSoftwareListCreate Permission = "ORGANIZATION_SOFTWARE_LIST_CREATE"
	// Grants the ability to modify an organization's existing software lists,
	// including adding, modifying, and removing components from individual software lists.
	PermissionOrganizationSoftwareListModify Permission = "ORGANIZATION_SOFTWARE_LIST_MODIFY"
	// Grants the ability to view an organization's software lists and any components they contain.
	// This also includes the ability to export an SBOM for the software lists and view risk scoring data.
	PermissionOrganizationSoftwareListView Permission = "ORGANIZATION_SOFTWARE_LIST_VIEW"
	// Grants the ability to remove software lists from an organization's software inventory.
	PermissionOrganizationSoftwareListRemove Permission = "ORGANIZATION_SOFTWARE_LIST_REMOVE"
)

var AllPermission = []Permission{
	PermissionAllPermissions,
	PermissionOrganizationModify,
	PermissionOrganizationView,
	PermissionOrganizationUserCreate,
	PermissionOrganizationUserModify,
	PermissionOrganizationUserRemove,
	PermissionOrganizationUserView,
	PermissionOrganizationSoftwareListCreate,
	PermissionOrganizationSoftwareListModify,
	PermissionOrganizationSoftwareListView,
	PermissionOrganizationSoftwareListRemove,
}

func (e Permission) IsValid() bool {
	switch e {
	case PermissionAllPermissions, PermissionOrganizationModify, PermissionOrganizationView, PermissionOrganizationUserCreate, PermissionOrganizationUserModify, PermissionOrganizationUserRemove, PermissionOrganizationUserView, PermissionOrganizationSoftwareListCreate, PermissionOrganizationSoftwareListModify, PermissionOrganizationSoftwareListView, PermissionOrganizationSoftwareListRemove:
		return true
	}
	return false
}

func (e Permission) String() string {
	return string(e)
}

func (e *Permission) UnmarshalGQL(v interface{}) error {
	str, ok := v.(string)
	if !ok {
		return fmt.Errorf("enums must be strings")
	}

	*e = Permission(str)
	if !e.IsValid() {
		return fmt.Errorf("%s is not a valid Permission", str)
	}
	return nil
}

func (e Permission) MarshalGQL(w io.Writer) {
	fmt.Fprint(w, strconv.Quote(e.String()))
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"time"

	"github.com/awslabs/aws-sdk-go/aws"
	"github.com/awslabs/aws-sdk-go/service/ec2"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsVpcPeeringConnection() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsVpcPeeringCreate,
		Read:   resourceAwsVpcPeeringRead,
		Update: resourceAwsVpcPeeringUpdate,
		Delete: resourceAwsVpcPeeringDelete,

		Schema: map[string]*schema.Schema{
			"peer_owner_id": &schema.Schema{
				Type:        schema.TypeString,
				Required:    true,
				ForceNew:    true,
				DefaultFunc: schema.EnvDefaultFunc("AWS_ACCOUNT_ID", nil),
			},
			"peer_vpc_id": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"vpc_id": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"auto_accept": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
			},
			"accept_status": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"tags": tagsSchema(),
		},
	}
}

func resourceAwsVpcPeeringCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn

	// Create the vpc peering connection
	createOpts := &ec2.CreateVPCPeeringConnectionInput{
		PeerOwnerID: aws.String(d.Get("peer_owner_id").(string)),
		PeerVPCID:   aws.String(d.Get("peer_vpc_id").(string)),
		VPCID:       aws.String(d.Get("vpc_id").(string)),
	}
	log.Printf("[DEBUG] VpcPeeringCreate create config: %#v", createOpts)
	resp, err := conn.CreateVPCPeeringConnection(createOpts)
	if err != nil {
		return fmt.Errorf("Error creating vpc peering connection: %s", err)
	}

	// Get the ID and store it
	rt := resp.VPCPeeringConnection
	d.SetId(*rt.VPCPeeringConnectionID)
	log.Printf("[INFO] Vpc Peering Connection ID: %s", d.Id())

	// Wait for the vpc peering connection to become available
	log.Printf(
		"[DEBUG] Waiting for vpc peering connection (%s) to become available",
		d.Id())
	stateConf := &resource.StateChangeConf{
		Pending: []string{"pending"},
		Target:  "ready",
		Refresh: resourceAwsVpcPeeringConnectionStateRefreshFunc(conn, d.Id()),
		Timeout: 1 * time.Minute,
	}
	if _, err := stateConf.WaitForState(); err != nil {
		return fmt.Errorf(
			"Error waiting for vpc peering (%s) to become available: %s",
			d.Id(), err)
	}

	return resourceAwsVpcPeeringUpdate(d, meta)
}

func resourceAwsVpcPeeringRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn
	pcRaw, _, err := resourceAwsVpcPeeringConnectionStateRefreshFunc(conn, d.Id())()
	if err != nil {
		return err
	}
	if pcRaw == nil {
		d.SetId("")
		return nil
	}

	pc := pcRaw.(*ec2.VPCPeeringConnection)

	if d.Get("auto_accept").(bool) {
		resourceVpcPeeringConnectionAccept(ec2conn, pc, d)
	} else {
		d.Set("accept_status", pc.Status.Code)
	}

	d.Set("peer_owner_id", pc.AccepterVpcInfo.OwnerId)
	d.Set("peer_vpc_id", pc.AccepterVpcInfo.VpcId)
	d.Set("vpc_id", pc.RequesterVpcInfo.VpcId)
	d.Set("tags", tagsToMap(pc.Tags))

	return nil
}

func resourceVpcPeeringConnectionAccept(conn *ec2.EC2, oldPc *ec2.VpcPeeringConnection, d *schema.ResourceData) error {
	if oldPc.Status.Code == "pending-acceptance" {
		log.Printf("[INFO] Accept Vpc Peering Connection with id: %s", d.Id())
		_, err := conn.AcceptVpcPeeringConnection(d.Id())
		if err != nil {
			return fmt.Errorf("Error accepting vpc peering connection: %s", err)
		}

		pcRaw, _, err := resourceAwsVpcPeeringConnectionStateRefreshFunc(conn, d.Id())()
		if err != nil {
			return err
		}
		if pcRaw == nil {
			d.SetId("")
			return nil
		}

		pc := pcRaw.(*ec2.VpcPeeringConnection)
		d.Set("accept_status", pc.Status.Code)

	}

	return nil
}

func resourceAwsVpcPeeringUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn

	if err := setTagsSDK(conn, d); err != nil {
		return err
	} else {
		d.SetPartial("tags")
	}

	return resourceAwsVpcPeeringRead(d, meta)
}

func resourceAwsVpcPeeringDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn

	_, err := conn.DeleteVPCPeeringConnection(
		&ec2.DeleteVPCPeeringConnectionInput{
			VPCPeeringConnectionID: aws.String(d.Id()),
		})
	return err
}

// resourceAwsVpcPeeringConnectionStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch
// a VpcPeeringConnection.
func resourceAwsVpcPeeringConnectionStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {

		resp, err := conn.DescribeVPCPeeringConnections(&ec2.DescribeVPCPeeringConnectionsInput{
			VPCPeeringConnectionIDs: []*string{aws.String(id)},
		})
		if err != nil {
			if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidVpcPeeringConnectionID.NotFound" {
				resp = nil
			} else {
				log.Printf("Error on VpcPeeringConnectionStateRefresh: %s", err)
				return nil, "", err
			}
		}

		if resp == nil {
			// Sometimes AWS just has consistency issues and doesn't see
			// our instance yet. Return an empty state.
			return nil, "", nil
		}

		pc := resp.VPCPeeringConnections[0]

		return pc, "ready", nil
	}
}
<commit_msg>clean code<commit_after>package aws

import (
	"fmt"
	"log"
	"time"

	"github.com/awslabs/aws-sdk-go/aws"
	"github.com/awslabs/aws-sdk-go/service/ec2"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsVpcPeeringConnection() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsVpcPeeringCreate,
		Read:   resourceAwsVpcPeeringRead,
		Update: resourceAwsVpcPeeringUpdate,
		Delete: resourceAwsVpcPeeringDelete,

		Schema: map[string]*schema.Schema{
			"peer_owner_id": &schema.Schema{
				Type:        schema.TypeString,
				Required:    true,
				ForceNew:    true,
				DefaultFunc: schema.EnvDefaultFunc("AWS_ACCOUNT_ID", nil),
			},
			"peer_vpc_id": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"vpc_id": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"auto_accept": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
			},
			"accept_status": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"tags": tagsSchema(),
		},
	}
}

func resourceAwsVpcPeeringCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn

	// Create the vpc peering connection
	createOpts := &ec2.CreateVPCPeeringConnectionInput{
		PeerOwnerID: aws.String(d.Get("peer_owner_id").(string)),
		PeerVPCID:   aws.String(d.Get("peer_vpc_id").(string)),
		VPCID:       aws.String(d.Get("vpc_id").(string)),
	}
	log.Printf("[DEBUG] VpcPeeringCreate create config: %#v", createOpts)
	resp, err := conn.CreateVPCPeeringConnection(createOpts)
	if err != nil {
		return fmt.Errorf("Error creating vpc peering connection: %s", err)
	}

	// Get the ID and store it
	rt := resp.VPCPeeringConnection
	d.SetId(*rt.VPCPeeringConnectionID)
	log.Printf("[INFO] Vpc Peering Connection ID: %s", d.Id())

	// Wait for the vpc peering connection to become available
	log.Printf(
		"[DEBUG] Waiting for vpc peering connection (%s) to become available",
		d.Id())
	stateConf := &resource.StateChangeConf{
		Pending: []string{"pending"},
		Target:  "ready",
		Refresh: resourceAwsVpcPeeringConnectionStateRefreshFunc(conn, d.Id()),
		Timeout: 1 * time.Minute,
	}
	if _, err := stateConf.WaitForState(); err != nil {
		return fmt.Errorf(
			"Error waiting for vpc peering (%s) to become available: %s",
			d.Id(), err)
	}

	return resourceAwsVpcPeeringUpdate(d, meta)
}

func resourceAwsVpcPeeringRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn
	pcRaw, _, err := resourceAwsVpcPeeringConnectionStateRefreshFunc(conn, d.Id())()
	if err != nil {
		return err
	}
	if pcRaw == nil {
		d.SetId("")
		return nil
	}

	pc := pcRaw.(*ec2.VPCPeeringConnection)

        code := pc.Status.Code
        if _, ok := d.GetOk("auto_accept"); ok {
                updatedCode, err := resourceVpcPeeringConnectionAccept(ec2conn, pc, d.Id())
                if err != nil {
                        return fmt.Errorf("Error accepting vpc peering connection: %s", err)
                }

                code = updatedCode
	}

        d.Set("accept_status", code)

	d.Set("peer_owner_id", pc.AccepterVpcInfo.OwnerId)
	d.Set("peer_vpc_id", pc.AccepterVpcInfo.VpcId)
	d.Set("vpc_id", pc.RequesterVpcInfo.VpcId)
	d.Set("tags", tagsToMap(pc.Tags))

	return nil
}

func resourceVpcPeeringConnectionAccept(conn *ec2.EC2, oldPc *ec2.VpcPeeringConnection, id string) (string, error) {
        //func resourceVpcPeeringConnectionAccept(conn *ec2.EC2, oldPc *ec2.VpcPeeringConnection, d *schema.ResourceData) error {
	if oldPc.Status.Code == "pending-acceptance" {
                log.Printf("[INFO] Accept Vpc Peering Connection with id: %s", id)
                _, err := conn.AcceptVpcPeeringConnection(id)

                pcRaw, _, err := resourceAwsVpcPeeringConnectionStateRefreshFunc(conn, id)()
		pc := pcRaw.(*ec2.VpcPeeringConnection)
                return pc.Status.Code, err
	}

        return oldPc.Status.Code, nil
}

func resourceAwsVpcPeeringUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn

	if err := setTagsSDK(conn, d); err != nil {
		return err
	} else {
		d.SetPartial("tags")
	}

	return resourceAwsVpcPeeringRead(d, meta)
}

func resourceAwsVpcPeeringDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn

	_, err := conn.DeleteVPCPeeringConnection(
		&ec2.DeleteVPCPeeringConnectionInput{
			VPCPeeringConnectionID: aws.String(d.Id()),
		})
	return err
}

// resourceAwsVpcPeeringConnectionStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch
// a VpcPeeringConnection.
func resourceAwsVpcPeeringConnectionStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {

		resp, err := conn.DescribeVPCPeeringConnections(&ec2.DescribeVPCPeeringConnectionsInput{
			VPCPeeringConnectionIDs: []*string{aws.String(id)},
		})
		if err != nil {
			if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidVpcPeeringConnectionID.NotFound" {
				resp = nil
			} else {
				log.Printf("Error on VpcPeeringConnectionStateRefresh: %s", err)
				return nil, "", err
			}
		}

		if resp == nil {
			// Sometimes AWS just has consistency issues and doesn't see
			// our instance yet. Return an empty state.
			return nil, "", nil
		}

		pc := resp.VPCPeeringConnections[0]

		return pc, "ready", nil
	}
}
<|endoftext|>