<commit_before>// Automatically downloads and configures Steam grid images for all games in a
// given Steam installation.
package main

import (
	"image"
	"image/draw"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"image/jpeg"
	_ "image/png"
)

// User in the local steam installation.
type User struct {
	Name string
	Dir  string
}

// Given the Steam installation dir (NOT the library!), returns all users in
// this computer.
func GetUsers(installationDir string) ([]User, error) {
	userdataDir := filepath.Join(installationDir, "userdata")
	files, err := ioutil.ReadDir(userdataDir)
	if err != nil {
		return nil, err
	}

	users := make([]User, 0)

	for _, userDir := range files {
		userId := userDir.Name()
		userDir := filepath.Join(userdataDir, userId)

		configFile := filepath.Join(userDir, "config", "localconfig.vdf")
		configBytes, err := ioutil.ReadFile(configFile)
		if err != nil {
			return nil, err
		}

		pattern := regexp.MustCompile(`"PersonaName"\s*"(.+?)"`)
		username := pattern.FindStringSubmatch(string(configBytes))[1]
		users = append(users, User{username, userDir})
	}

	return users, nil
}

// Steam profile URL format.
const urlFormat = `http://steamcommunity.com/id/%v/games?tab=all`

// Returns the public Steam profile for a given user, in HTML.
func GetProfile(username string) (string, error) {
	response, err := http.Get(fmt.Sprintf(urlFormat, username))
	if err != nil {
		return "", err
	}

	contentBytes, err := ioutil.ReadAll(response.Body)
	response.Body.Close()
	if err != nil {
		return "", err
	}

	return string(contentBytes), nil
}

// A Steam game in a library. May or may not be installed.
type Game struct {
	// Official Steam id.
	Id string
	// Warning, may contain Unicode characters.
	Name string
	// User created category. May be blank.
	Category string
	// Path for the grid image.
	ImagePath string
}

// Pattern of game declarations in the public profile. It's actually JSON
// inside Javascript, but this way is easier to extract.
const profileGamePattern = `\{"appid":\s*(\d+),\s*"name":\s*"(.+?)"`

// Returns all games from a given user, using both the public profile and local
// files to gather the data. Returns a map of game by ID.
func GetGames(user User) (map[string]*Game, error) {
	profile, err := GetProfile(user.Name)
	if err != nil {
		return nil, err
	}

	// Fetch game list from public profile.
	pattern := regexp.MustCompile(profileGamePattern)
	games := make(map[string]*Game, 0)
	for _, groups := range pattern.FindAllStringSubmatch(profile, -1) {
		gameId := groups[1]
		gameName := groups[2]
		category := ""
		imagePath := ""
		games[gameId] = &Game{gameId, gameName, category, imagePath}
	}

	// Fetch game categories from local file.
	sharedConfFile := filepath.Join(user.Dir, "7", "remote", "sharedconfig.vdf")
	sharedConfBytes, err := ioutil.ReadFile(sharedConfFile)

	sharedConf := string(sharedConfBytes)
	// VDF patterN: "steamid" { "tags { "0" "category" } }
	pattern = regexp.MustCompile(`"([0-9]+)"\s*{[^}]+?"tags"\s*{\s*"0"\s*"([^"]+)"`)
	for _, groups := range pattern.FindAllStringSubmatch(sharedConf, -1) {
		gameId := groups[1]
		category := groups[2]

		game, ok := games[gameId]
		if ok {
			game.Category = category
		} else {
			// If for some reason it wasn't included in the profile, create a new
			// entry for it now. Unfortunately we don't have a name.
			gameName := ""
			games[gameId] = &Game{gameId, gameName, category, ""}
		}
	}

	return games, nil
}

// When all else fails, Google it. Unfortunately this is a deprecated API and
// may go offline at any time. Because this is last resort the number of
// requests shouldn't trigger any punishment.
const googleSearchFormat = `https://ajax.googleapis.com/ajax/services/search/images?v=1.0&q=`

// Returns the first steam grid image URL found by Google search of a given
// game name.
func getGoogleImage(gameName string) (string, error) {
	url := googleSearchFormat + url.QueryEscape("steam grid OR header"+gameName)
	response, err := http.Get(url)
	if err != nil {
		return "", err
	}

	responseBytes, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return "", err
	}
	response.Body.Close()
	// Again, we could parse JSON. This may be a little too lazy, the pattern
	// is very loose. The order could be wrong, for example.
	pattern := regexp.MustCompile(`"width":"460","height":"215",[^}]+"unescapedUrl":"(.+?)"`)
	matches := pattern.FindStringSubmatch(string(responseBytes))
	if len(matches) >= 1 {
		return matches[0], nil
	} else {
		return "", nil
	}
}

// Tries to fetch a URL, returning the response only if it was positive.
func tryDownload(url string) (*http.Response, error) {
	response, err := http.Get(url)
	if err != nil {
		return nil, err
	}

	if response.StatusCode == 404 {
		// Some apps don't have an image and there's nothing we can do.
		return nil, nil
	} else if response.StatusCode > 400 {
		// Other errors should be reported, though.
		return nil, errors.New("Failed to download image " + url + ": " + response.Status)
	}

	return response, nil
}

// Primary URL for downloading grid images.
const akamaiUrlFormat = `https://steamcdn-a.akamaihd.net/steam/apps/%v/header.jpg`

// The subreddit mentions this as primary, but I've found Akamai to contain
// more images and answer faster.
const steamCdnUrlFormat = `http://cdn.steampowered.com/v/gfx/apps/%v/header.jpg`

// Tries to load the grid image for a game from a number of alternative
// sources. Returns the final response received and a flag indicating if it was
// fro ma Google search (useful because we want to log the lower quality
// images).
func getImageAlternatives(game *Game) (response *http.Response, fromSearch bool, err error) {
	response, err = tryDownload(fmt.Sprintf(akamaiUrlFormat, game.Id))
	if err == nil && response != nil {
		return
	}

	response, err = tryDownload(fmt.Sprintf(steamCdnUrlFormat, game.Id))
	if err == nil && response != nil {
		return
	}

	fromSearch = true
	url, err := getGoogleImage(game.Name)
	if err != nil {
		return
	}
	response, err = tryDownload(url)
	if err == nil && response != nil {
		return
	}

	return nil, false, nil
}

// Downloads the grid image for a game into the user's grid directory. Returns
// flags indicating if the operation succeeded and if the image downloaded was
// from a search.
func DownloadImage(game *Game, user User) (found bool, fromSearch bool, err error) {
	gridDir := filepath.Join(user.Dir, "config", "grid")
	filename := filepath.Join(gridDir, game.Id+".jpg")

	game.ImagePath = filename
	if _, err := os.Stat(filename); err == nil {
		// File already exists, skip it.
		return true, false, nil
	}

	response, fromSearch, err := getImageAlternatives(game)
	if response == nil || err != nil {
		return false, false, err
	}

	imageBytes, err := ioutil.ReadAll(response.Body)
	response.Body.Close()
	return true, fromSearch, ioutil.WriteFile(filename, imageBytes, 0666)
}

// Loads an image from a given path.
func loadImage(path string) (img image.Image, err error) {
	reader, err := os.Open(path)
	if err != nil {
		return
	}
	defer reader.Close()

	img, _, err = image.Decode(reader)
	return
}
// Loads the overlays from the given dir, returning a map of name -> image.
func LoadOverlays(dir string) (overlays map[string]image.Image, err error) {

	files, err := ioutil.ReadDir(dir)
	if err != nil {
		return
	}

	overlays = make(map[string]image.Image, 0)

	for _, file := range files {
		img, err := loadImage(filepath.Join(dir, file.Name()))
		if err != nil {
			return nil, err
		}

		// Normalize overlay name.
		name := strings.TrimSuffix(file.Name(), filepath.Ext(file.Name()))
		overlays[strings.ToLower(name)] = img
	}

	return
}

// Applies an overlay to the game image, depending on the category. The
// resulting image is saved over the original.
func ApplyOverlay(game *Game, overlays map[string]image.Image) (err error) {
	if game.ImagePath == "" {
		return nil
	}

	if _, err := os.Stat(game.ImagePath); err != nil {
		// Game has no image, we have to skip it.
		return nil
	}

	// Normalize overlay name.
	categoryName := strings.ToLower(game.Category)

	overlayImage, ok := overlays[categoryName]
	if !ok {
		return
	}

	gameImage, err := loadImage(game.ImagePath)
	if err != nil {
		return err
	}

    result := image.NewRGBA(gameImage.Bounds().Union(overlayImage.Bounds()))
    draw.Draw(result, result.Bounds(), gameImage, image.ZP, draw.Src)
    draw.Draw(result, result.Bounds(), overlayImage, image.Point{0,0}, draw.Over)

	ext := filepath.Ext(game.ImagePath)
	backupPath := strings.TrimSuffix(game.ImagePath, ext) + " (original)" + ext
	if _, err := os.Stat(backupPath); err != nil {
		// Backup doesn't exist, create it.
		err = os.Rename(game.ImagePath, backupPath)
		if err != nil {
			return err
		}
	}

    resultFile, _ := os.Create(game.ImagePath)
    defer resultFile.Close()
    return jpeg.Encode(resultFile, result, &jpeg.Options{90})
}

// Returns the Steam installation directory in Windows. Should work for
// internationalized systems, 32 and 64 bits and users that moved their
// ProgramFiles folder. If a folder is given by program parameter, uses that.
func GetSteamInstallation() (path string, err error) {
	if len(os.Args) == 2 {
		argDir := os.Args[1]
		_, err := os.Stat(argDir)
		if err == nil {
			return argDir, nil
		} else {
			return "", errors.New("Argument must be a valid Steam directory, or empty for auto detection. Got: " + argDir)
		}
	}

	programFiles86Dir := filepath.Join(os.Getenv("ProgramFiles(x86)"), "Steam")
	if _, err = os.Stat(programFiles86Dir); err == nil {
		return programFiles86Dir, nil
	}

	programFilesDir := filepath.Join(os.Getenv("ProgramFiles"), "Steam")
	if _, err = os.Stat(programFilesDir); err == nil {
		return programFilesDir, nil
	}

	return "", errors.New("Could not find Steam installation folder.")
}

// Prints a progress bar, overriding the previous line. It looks like this:
// [=========>        ] (50/100)
func PrintProgress(current int, total int) {
	// \r moves the cursor back to the start of the line.
	fmt.Print("\r[")

	printedHead := false
	for i := 0; i < 40; i++ {
		part := int(float64(i) * (float64(total) / 40.0))
		if part < current {
			fmt.Print("=")
		} else if !printedHead {
			printedHead = true
			fmt.Print(">")
		} else {
			fmt.Print(" ")
		}
	}

	fmt.Printf("] (%v/%v)", current, total)
}

// Prints an error and quits.
func errorAndExit(err error) {
	fmt.Println("An unexpected error occurred:")
	fmt.Println(err)
	os.Exit(1)
}

func main() {
	overlays, err := LoadOverlays("overlays by category")
	if err != nil {
		errorAndExit(err)
	}

	installationDir, err := GetSteamInstallation()
	if err != nil {
		errorAndExit(err)
	}

	users, err := GetUsers(installationDir)
	if err != nil {
		errorAndExit(err)
	}

	for _, user := range users {
		fmt.Printf("Found user %v. Fetching game list from profile...\n\n\n", user.Name)

		games, err := GetGames(user)
		if err != nil {
			errorAndExit(err)
		}

		notFounds := make([]*Game, 0)
		searchFounds := make([]*Game, 0)
		fmt.Printf("Found %v games. Downloading images...\n\n", len(games))

		i := 0
		for _, game := range games {
			i++
			PrintProgress(i, len(games))
			found, fromSearch, err := DownloadImage(game, user)
			if err != nil {
				errorAndExit(err)
			}
			if !found {
				notFounds = append(notFounds, game)
				continue
			}
			if fromSearch {
				searchFounds = append(searchFounds, game)
			}

			err = ApplyOverlay(game, overlays)
			if err != nil {
				errorAndExit(err)
			}
		}
		fmt.Print("\n\n\n")

		if len(notFounds) == 0 && len(searchFounds) == 0 {
			fmt.Println("All grid images downloaded!")
		} else {
			if len(searchFounds) >= 1 {
				fmt.Printf("%v images were found with a Google search and may not be accurate:.\n", len(searchFounds))
				for _, game := range searchFounds {
					fmt.Printf("* %v (steam id %v)\n", game.Name, game.Id)
				}
			}

			fmt.Print("\n\n")

			if len(notFounds) >= 1 {
				fmt.Printf("%v images could not be found:\n", len(notFounds))
				for _, game := range notFounds {
					fmt.Printf("* %v (steam id %v)\n", game.Name, game.Id)
				}
			}
		}
	}

	fmt.Print("\n\n")
	fmt.Println("You can press enter to close this window.")
	os.Stdin.Read(make([]byte, 1))
}
<commit_msg>Don't quit after finding an error<commit_after>// Automatically downloads and configures Steam grid images for all games in a
// given Steam installation.
package main

import (
	"image"
	"image/draw"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"image/jpeg"
	_ "image/png"
)

// User in the local steam installation.
type User struct {
	Name string
	Dir  string
}

// Given the Steam installation dir (NOT the library!), returns all users in
// this computer.
func GetUsers(installationDir string) ([]User, error) {
	userdataDir := filepath.Join(installationDir, "userdata")
	files, err := ioutil.ReadDir(userdataDir)
	if err != nil {
		return nil, err
	}

	users := make([]User, 0)

	for _, userDir := range files {
		userId := userDir.Name()
		userDir := filepath.Join(userdataDir, userId)

		configFile := filepath.Join(userDir, "config", "localconfig.vdf")
		configBytes, err := ioutil.ReadFile(configFile)
		if err != nil {
			return nil, err
		}

		pattern := regexp.MustCompile(`"PersonaName"\s*"(.+?)"`)
		username := pattern.FindStringSubmatch(string(configBytes))[1]
		users = append(users, User{username, userDir})
	}

	return users, nil
}

// Steam profile URL format.
const urlFormat = `http://steamcommunity.com/id/%v/games?tab=all`

// Returns the public Steam profile for a given user, in HTML.
func GetProfile(username string) (string, error) {
	response, err := http.Get(fmt.Sprintf(urlFormat, username))
	if err != nil {
		return "", err
	}

	contentBytes, err := ioutil.ReadAll(response.Body)
	response.Body.Close()
	if err != nil {
		return "", err
	}

	return string(contentBytes), nil
}

// A Steam game in a library. May or may not be installed.
type Game struct {
	// Official Steam id.
	Id string
	// Warning, may contain Unicode characters.
	Name string
	// User created category. May be blank.
	Category string
	// Path for the grid image.
	ImagePath string
}

// Pattern of game declarations in the public profile. It's actually JSON
// inside Javascript, but this way is easier to extract.
const profileGamePattern = `\{"appid":\s*(\d+),\s*"name":\s*"(.+?)"`

// Returns all games from a given user, using both the public profile and local
// files to gather the data. Returns a map of game by ID.
func GetGames(user User) (map[string]*Game, error) {
	profile, err := GetProfile(user.Name)
	if err != nil {
		return nil, err
	}

	// Fetch game list from public profile.
	pattern := regexp.MustCompile(profileGamePattern)
	games := make(map[string]*Game, 0)
	for _, groups := range pattern.FindAllStringSubmatch(profile, -1) {
		gameId := groups[1]
		gameName := groups[2]
		category := ""
		imagePath := ""
		games[gameId] = &Game{gameId, gameName, category, imagePath}
	}

	// Fetch game categories from local file.
	sharedConfFile := filepath.Join(user.Dir, "7", "remote", "sharedconfig.vdf")
	sharedConfBytes, err := ioutil.ReadFile(sharedConfFile)

	sharedConf := string(sharedConfBytes)
	// VDF patterN: "steamid" { "tags { "0" "category" } }
	pattern = regexp.MustCompile(`"([0-9]+)"\s*{[^}]+?"tags"\s*{\s*"0"\s*"([^"]+)"`)
	for _, groups := range pattern.FindAllStringSubmatch(sharedConf, -1) {
		gameId := groups[1]
		category := groups[2]

		game, ok := games[gameId]
		if ok {
			game.Category = category
		} else {
			// If for some reason it wasn't included in the profile, create a new
			// entry for it now. Unfortunately we don't have a name.
			gameName := ""
			games[gameId] = &Game{gameId, gameName, category, ""}
		}
	}

	return games, nil
}

// When all else fails, Google it. Unfortunately this is a deprecated API and
// may go offline at any time. Because this is last resort the number of
// requests shouldn't trigger any punishment.
const googleSearchFormat = `https://ajax.googleapis.com/ajax/services/search/images?v=1.0&q=`

// Returns the first steam grid image URL found by Google search of a given
// game name.
func getGoogleImage(gameName string) (string, error) {
	url := googleSearchFormat + url.QueryEscape("steam grid OR header"+gameName)
	response, err := http.Get(url)
	if err != nil {
		return "", err
	}

	responseBytes, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return "", err
	}
	response.Body.Close()
	// Again, we could parse JSON. This may be a little too lazy, the pattern
	// is very loose. The order could be wrong, for example.
	pattern := regexp.MustCompile(`"width":"460","height":"215",[^}]+"unescapedUrl":"(.+?)"`)
	matches := pattern.FindStringSubmatch(string(responseBytes))
	if len(matches) >= 1 {
		return matches[0], nil
	} else {
		return "", nil
	}
}

// Tries to fetch a URL, returning the response only if it was positive.
func tryDownload(url string) (*http.Response, error) {
	response, err := http.Get(url)
	if err != nil {
		return nil, err
	}

	if response.StatusCode == 404 {
		// Some apps don't have an image and there's nothing we can do.
		return nil, nil
	} else if response.StatusCode > 400 {
		// Other errors should be reported, though.
		return nil, errors.New("Failed to download image " + url + ": " + response.Status)
	}

	return response, nil
}

// Primary URL for downloading grid images.
const akamaiUrlFormat = `https://steamcdn-a.akamaihd.net/steam/apps/%v/header.jpg`

// The subreddit mentions this as primary, but I've found Akamai to contain
// more images and answer faster.
const steamCdnUrlFormat = `http://cdn.steampowered.com/v/gfx/apps/%v/header.jpg`

// Tries to load the grid image for a game from a number of alternative
// sources. Returns the final response received and a flag indicating if it was
// fro ma Google search (useful because we want to log the lower quality
// images).
func getImageAlternatives(game *Game) (response *http.Response, fromSearch bool, err error) {
	response, err = tryDownload(fmt.Sprintf(akamaiUrlFormat, game.Id))
	if err == nil && response != nil {
		return
	}

	response, err = tryDownload(fmt.Sprintf(steamCdnUrlFormat, game.Id))
	if err == nil && response != nil {
		return
	}

	fromSearch = true
	url, err := getGoogleImage(game.Name)
	if err != nil {
		return
	}
	response, err = tryDownload(url)
	if err == nil && response != nil {
		return
	}

	return nil, false, nil
}

// Downloads the grid image for a game into the user's grid directory. Returns
// flags indicating if the operation succeeded and if the image downloaded was
// from a search.
func DownloadImage(game *Game, user User) (found bool, fromSearch bool, err error) {
	gridDir := filepath.Join(user.Dir, "config", "grid")
	filename := filepath.Join(gridDir, game.Id+".jpg")

	game.ImagePath = filename
	if _, err := os.Stat(filename); err == nil {
		// File already exists, skip it.
		return true, false, nil
	}

	response, fromSearch, err := getImageAlternatives(game)
	if response == nil || err != nil {
		return false, false, err
	}

	imageBytes, err := ioutil.ReadAll(response.Body)
	response.Body.Close()
	return true, fromSearch, ioutil.WriteFile(filename, imageBytes, 0666)
}

// Loads an image from a given path.
func loadImage(path string) (img image.Image, err error) {
	reader, err := os.Open(path)
	if err != nil {
		return
	}
	defer reader.Close()

	img, _, err = image.Decode(reader)
	return
}
// Loads the overlays from the given dir, returning a map of name -> image.
func LoadOverlays(dir string) (overlays map[string]image.Image, err error) {

	files, err := ioutil.ReadDir(dir)
	if err != nil {
		return
	}

	overlays = make(map[string]image.Image, 0)

	for _, file := range files {
		img, err := loadImage(filepath.Join(dir, file.Name()))
		if err != nil {
			return nil, err
		}

		// Normalize overlay name.
		name := strings.TrimSuffix(file.Name(), filepath.Ext(file.Name()))
		overlays[strings.ToLower(name)] = img
	}

	return
}

// Applies an overlay to the game image, depending on the category. The
// resulting image is saved over the original.
func ApplyOverlay(game *Game, overlays map[string]image.Image) (err error) {
	if game.ImagePath == "" {
		return nil
	}

	if _, err := os.Stat(game.ImagePath); err != nil {
		// Game has no image, we have to skip it.
		return nil
	}

	// Normalize overlay name.
	categoryName := strings.ToLower(game.Category)

	overlayImage, ok := overlays[categoryName]
	if !ok {
		return
	}

	gameImage, err := loadImage(game.ImagePath)
	if err != nil {
		return err
	}

    result := image.NewRGBA(gameImage.Bounds().Union(overlayImage.Bounds()))
    draw.Draw(result, result.Bounds(), gameImage, image.ZP, draw.Src)
    draw.Draw(result, result.Bounds(), overlayImage, image.Point{0,0}, draw.Over)

	ext := filepath.Ext(game.ImagePath)
	backupPath := strings.TrimSuffix(game.ImagePath, ext) + " (original)" + ext
	if _, err := os.Stat(backupPath); err != nil {
		// Backup doesn't exist, create it.
		err = os.Rename(game.ImagePath, backupPath)
		if err != nil {
			return err
		}
	}

    resultFile, _ := os.Create(game.ImagePath)
    defer resultFile.Close()
    return jpeg.Encode(resultFile, result, &jpeg.Options{90})
}

// Returns the Steam installation directory in Windows. Should work for
// internationalized systems, 32 and 64 bits and users that moved their
// ProgramFiles folder. If a folder is given by program parameter, uses that.
func GetSteamInstallation() (path string, err error) {
	if len(os.Args) == 2 {
		argDir := os.Args[1]
		_, err := os.Stat(argDir)
		if err == nil {
			return argDir, nil
		} else {
			return "", errors.New("Argument must be a valid Steam directory, or empty for auto detection. Got: " + argDir)
		}
	}

	programFiles86Dir := filepath.Join(os.Getenv("ProgramFiles(x86)"), "Steam")
	if _, err = os.Stat(programFiles86Dir); err == nil {
		return programFiles86Dir, nil
	}

	programFilesDir := filepath.Join(os.Getenv("ProgramFiles"), "Steam")
	if _, err = os.Stat(programFilesDir); err == nil {
		return programFilesDir, nil
	}

	return "", errors.New("Could not find Steam installation folder.")
}

// Prints a progress bar, overriding the previous line. It looks like this:
// [=========>        ] (50/100)
func PrintProgress(current int, total int) {
	// \r moves the cursor back to the start of the line.
	fmt.Print("\r[")

	printedHead := false
	for i := 0; i < 40; i++ {
		part := int(float64(i) * (float64(total) / 40.0))
		if part < current {
			fmt.Print("=")
		} else if !printedHead {
			printedHead = true
			fmt.Print(">")
		} else {
			fmt.Print(" ")
		}
	}

	fmt.Printf("] (%v/%v)", current, total)
}

// Prints an error and quits.
func errorAndExit(err error) {
	fmt.Println("An unexpected error occurred:")
	fmt.Println(err)
	os.Stdin.Read(make([]byte, 1))
	os.Exit(1)
}

func main() {
	overlays, err := LoadOverlays("overlays by category")
	if err != nil {
		errorAndExit(err)
	}

	installationDir, err := GetSteamInstallation()
	if err != nil {
		errorAndExit(err)
	}

	users, err := GetUsers(installationDir)
	if err != nil {
		errorAndExit(err)
	}

	for _, user := range users {
		fmt.Printf("Found user %v. Fetching game list from profile...\n\n\n", user.Name)

		games, err := GetGames(user)
		if err != nil {
			errorAndExit(err)
		}

		notFounds := make([]*Game, 0)
		searchFounds := make([]*Game, 0)
		fmt.Printf("Found %v games. Downloading images...\n\n", len(games))

		i := 0
		for _, game := range games {
			i++
			PrintProgress(i, len(games))
			found, fromSearch, err := DownloadImage(game, user)
			if err != nil {
				errorAndExit(err)
			}
			if !found {
				notFounds = append(notFounds, game)
				continue
			}
			if fromSearch {
				searchFounds = append(searchFounds, game)
			}

			err = ApplyOverlay(game, overlays)
			if err != nil {
				errorAndExit(err)
			}
		}
		fmt.Print("\n\n\n")

		if len(notFounds) == 0 && len(searchFounds) == 0 {
			fmt.Println("All grid images downloaded!")
		} else {
			if len(searchFounds) >= 1 {
				fmt.Printf("%v images were found with a Google search and may not be accurate:.\n", len(searchFounds))
				for _, game := range searchFounds {
					fmt.Printf("* %v (steam id %v)\n", game.Name, game.Id)
				}
			}

			fmt.Print("\n\n")

			if len(notFounds) >= 1 {
				fmt.Printf("%v images could not be found:\n", len(notFounds))
				for _, game := range notFounds {
					fmt.Printf("* %v (steam id %v)\n", game.Name, game.Id)
				}
			}
		}
	}

	fmt.Print("\n\n")
	fmt.Println("You can press enter to close this window.")
	os.Stdin.Read(make([]byte, 1))
}
<|endoftext|>


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

package html

import (
	"fmt"
)

// context describes the state an HTML parser must be in when it reaches the
// portion of HTML produced by evaluating a particular template node.
//
// The zero value of type context is the start context for a template that
// produces an HTML fragment as defined at
// http://www.w3.org/TR/html5/the-end.html#parsing-html-fragments
// where the context element is null.
type context struct {
	state   state
	delim   delim
	urlPart urlPart
	jsCtx   jsCtx
	attr    attr
	element element
	err     *Error
}

// eq returns whether two contexts are equal.
func (c context) eq(d context) bool {
	return c.state == d.state &&
		c.delim == d.delim &&
		c.urlPart == d.urlPart &&
		c.jsCtx == d.jsCtx &&
		c.attr == d.attr &&
		c.element == d.element &&
		c.err == d.err
}

// mangle produces an identifier that includes a suffix that distinguishes it
// from template names mangled with different contexts.
func (c context) mangle(templateName string) string {
	// The mangled name for the default context is the input templateName.
	if c.state == stateText {
		return templateName
	}
	s := templateName + "$htmltemplate_" + c.state.String()
	if c.delim != 0 {
		s += "_" + c.delim.String()
	}
	if c.urlPart != 0 {
		s += "_" + c.urlPart.String()
	}
	if c.jsCtx != 0 {
		s += "_" + c.jsCtx.String()
	}
	if c.attr != 0 {
		s += "_" + c.attr.String()
	}
	if c.element != 0 {
		s += "_" + c.element.String()
	}
	return s
}

// state describes a high-level HTML parser state.
//
// It bounds the top of the element stack, and by extension the HTML insertion
// mode, but also contains state that does not correspond to anything in the
// HTML5 parsing algorithm because a single token production in the HTML
// grammar may contain embedded actions in a template. For instance, the quoted
// HTML attribute produced by
//

// is a single token in HTML's grammar but in a template spans several nodes.
type state uint8

const (
	// stateText is parsed character data. An HTML parser is in
	// this state when its parse position is outside an HTML tag,
	// directive, comment, and special element body.
	stateText state = iota
	// stateTag occurs before an HTML attribute or the end of a tag.
	stateTag
	// stateAttrName occurs inside an attribute name.
	// It occurs between the ^'s in ` ^name^ = value`.
	stateAttrName
	// stateAfterName occurs after an attr name has ended but before any
	// equals sign. It occurs between the ^'s in ` name^ ^= value`.
	stateAfterName
	// stateBeforeValue occurs after the equals sign but before the value.
	// It occurs between the ^'s in ` name =^ ^value`.
	stateBeforeValue
	// stateHTMLCmt occurs inside an .
	stateHTMLCmt
	// stateRCDATA occurs inside an RCDATA element (<textarea> or <title>)
	// as described at http://dev.w3.org/html5/spec/syntax.html#elements-0
	stateRCDATA
	// stateAttr occurs inside an HTML attribute whose content is text.
	stateAttr
	// stateURL occurs inside an HTML attribute whose content is a URL.
	stateURL
	// stateJS occurs inside an event handler or script element.
	stateJS
	// stateJSDqStr occurs inside a JavaScript double quoted string.
	stateJSDqStr
	// stateJSSqStr occurs inside a JavaScript single quoted string.
	stateJSSqStr
	// stateJSRegexp occurs inside a JavaScript regexp literal.
	stateJSRegexp
	// stateJSBlockCmt occurs inside a JavaScript /* block comment */.
	stateJSBlockCmt
	// stateJSLineCmt occurs inside a JavaScript // line comment.
	stateJSLineCmt
	// stateCSS occurs inside a


<commit_before>package main

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"strings"

	"github.com/boltdb/bolt"
	"github.com/codegangsta/cli"
)

const (
	rubyBuildRepo = "https://github.com/rbenv/ruby-build.git"
)

var currentHome = os.Getenv("HOME")
var grvmRuby = os.Getenv("grvm_ruby")
var grvmDirectory = fmt.Sprintf("%s/.grvm", currentHome)
var rubyBuildDirectory = fmt.Sprintf("%s/ruby-build", grvmDirectory)
var rubyBuildExecutable = fmt.Sprintf("%s/bin/ruby-build", rubyBuildDirectory)
var rubiesHome = fmt.Sprintf("%s/rubies", grvmDirectory)
var dbPath = fmt.Sprintf("%s/grvm.db", grvmDirectory)

func getDB() (*bolt.DB, error) {
	return bolt.Open(dbPath, 0600, nil)
}

func Print(c *cli.Context, args ...string) {
	if c.GlobalBool("shell") {
		fmt.Println(fmt.Sprintf("echo %q", strings.Join(args, " ")))
	} else {
		fmt.Println(strings.Join(args, " "))
	}
}

func main() {
	app := cli.NewApp()
	app.Name = "RVM"
	app.Usage = "RVM"
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name: "shell, s",
		},
	}
	app.Commands = []cli.Command{
		{
			Name:    "env",
			Aliases: []string{"e"},
			Usage:   "Show env for ruby version",
			Action:  env,
		},
		{
			Name:    "set",
			Aliases: []string{"s"},
			Usage:   "Set current ruby",
			Action:  set,
			Flags: []cli.Flag{
				cli.BoolFlag{
					Name: "default, d",
				},
			},
		},
		{
			Name:    "doctor",
			Aliases: []string{"d"},
			Usage:   "Fixes all bugs",
			Action:  doctor,
		},
		{
			Name:    "update",
			Aliases: []string{"u"},
			Usage:   "Updates available rubies",
			Action:  update,
		},
		{
			Name:    "install",
			Aliases: []string{"i"},
			Usage:   "Instqalls ruby",
			Action:  install,
		},
	}

	app.Run(os.Args)
}

func env(c *cli.Context) {
	var currentRuby string

	if len(grvmRuby) == 0 {
		currentRuby = getDefaultRuby(c)
	} else {
		currentRuby = grvmRuby
	}

	switch currentRuby {
	case "system":
		fmt.Println("export grvm_ruby=system")
	default:
		printEnv(currentRuby)
	}
}

func getDefaultRuby(c *cli.Context) string {
	db, err := getDB()
	if err != nil {
		Print(c, "Cannot open database file")
		os.Exit(1)
	}
	defer db.Close()

	tx, err := db.Begin(true)
	if err != nil {
		Print(c, "Cannpt open database transaction")
		os.Exit(1)
	}
	defer tx.Rollback()

	var b *bolt.Bucket
	var e error
	b, e = tx.CreateBucket([]byte("settings"))
	if e == bolt.ErrBucketExists {
		b = tx.Bucket([]byte("settings"))
	} else if e != nil {
		Print(c, "Cannot create bucket for settings")
		os.Exit(1)
	}

	defaultRuby := b.Get([]byte("default"))

	if defaultRuby == nil {
		return "system"
	} else if len(defaultRuby) == 0 {
		return "system"
	} else {
		candidate := string(defaultRuby)

		if err := checkCandidate(tx, candidate); err != nil {
			Print(c, err.Error())
			return "system"
		} else {
			return candidate
		}
	}
}

func printEnv(rubyVersion string) {
	currentPathEnv := os.Getenv("PATH")
	newPaths := rebuildPaths(currentPathEnv, currentHome)

	if rubyVersion == "system" {
		fmt.Println(fmt.Sprintf("export PATH=%s", newPaths))
	} else {
		gemsRoot := fmt.Sprintf("%s/gems/%s", grvmDirectory, rubyVersion)

		fmt.Println(fmt.Sprintf("export GEM_HOME=%s", gemsRoot))
		fmt.Println(fmt.Sprintf("export GEM_PATH=%s", gemsRoot))

		currentRubyBin := fmt.Sprintf("%s/%s/bin", rubiesHome, rubyVersion)
		currentGemsBin := fmt.Sprintf("%s/bin", gemsRoot)

		path := fmt.Sprintf("%s:%s:%s", currentRubyBin, currentGemsBin, newPaths)
		fmt.Println(fmt.Sprintf("export PATH=%s", path))
	}

	fmt.Println(fmt.Sprintf("export grvm_ruby=%s", rubyVersion))
}

func rebuildPaths(path, home string) string {
	var paths = strings.Split(path, ":")
	var currentPath = fmt.Sprintf("%s/%s", home, ".grvm")
	var newPaths []string

	for _, p := range paths {
		if !strings.HasPrefix(p, currentPath) {
			newPaths = append(newPaths, p)
		}
	}

	return strings.Join(newPaths, ":")

}

func doctor(c *cli.Context) {
	if _, err := os.Stat(rubyBuildDirectory); os.IsNotExist(err) {
		installRubyBuild()
	}

	updateAvailableRubies()
}

func installRubyBuild() {
	fmt.Println("Install ruby-build")
	args := []string{"clone", "https://github.com/rbenv/ruby-build.git", rubyBuildDirectory}

	cmd := exec.Command("git", args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if err := cmd.Run(); err != nil {
		fmt.Println("something going wrong, try to clone ruby-build manually: git", strings.Join(args, " "))
		os.Exit(1)
	}
}

func set(c *cli.Context) {
	db, err := getDB()
	if err != nil {
		Print(c, "Cannot open database file:", dbPath)
		os.Exit(1)
	}
	defer db.Close()

	tx, err := db.Begin(true)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	defer tx.Rollback()

	var b *bolt.Bucket
	var e error
	b, e = tx.CreateBucket([]byte("settings"))
	if e == bolt.ErrBucketExists {
		b = tx.Bucket([]byte("settings"))
	} else if e != nil {
		Print(c, "Cannot create bucket for settings")
		os.Exit(1)
	}

	candidate := c.Args().Get(0)

	if len(candidate) == 0 {
		Print(c, "No version given")
		os.Exit(1)
	}

	if err := checkCandidate(tx, candidate); err != nil {
		Print(c, err.Error())
		os.Exit(1)
	}

	if c.Bool("default") {
		b.Put([]byte("default"), []byte(candidate))

		if err := tx.Commit(); err != nil {
			fmt.Println("Cannot save settings")
			os.Exit(1)
		}

		printEnv(candidate)
		Print(c, "Now,", candidate, "default ruby")
	} else {
		printEnv(candidate)
	}
}

func checkCandidate(tx *bolt.Tx, candidate string) error {
	rubies := tx.Bucket([]byte("rubies"))
	value := rubies.Get([]byte(candidate))

	if value == nil {
		return fmt.Errorf("No candidate to set: %s", candidate)
	} else if len(value) == 0 {
		return fmt.Errorf("%s not installed, please use: grvm install %s", candidate, candidate)
	}

	return nil
}

func update(c *cli.Context) {
	if err := os.Chdir(rubyBuildDirectory); err != nil {
		fmt.Println("Cannot switch directory to:", rubyBuildDirectory)
		os.Exit(1)
	}

	args := []string{"pull", "origin", "master"}

	cmd := exec.Command("git", args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if err := cmd.Run(); err != nil {
		fmt.Println("something going wrong, try to update ruby-build manually: git", strings.Join(args, " "))
		os.Exit(1)
	}

	updateAvailableRubies()
}

func updateAvailableRubies() {
	db, err := getDB()
	if err != nil {
		fmt.Println("Cannot open database file:", dbPath)
		os.Exit(1)
	}
	defer db.Close()

	tx, err := db.Begin(true)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	defer tx.Rollback()

	var b *bolt.Bucket
	var e error
	b, e = tx.CreateBucket([]byte("rubies"))
	if e == bolt.ErrBucketExists {
		b = tx.Bucket([]byte("rubies"))
	} else if e != nil {
		fmt.Println(err)
		fmt.Println("Cannot create bucket for rubies")
		os.Exit(1)
	}

	buffer := bytes.NewBuffer(make([]byte, 0))

	cmd := exec.Command(rubyBuildExecutable, "--definitions")
	cmd.Stdout = buffer
	cmd.Stderr = buffer

	if err := cmd.Run(); err != nil {
		os.Exit(1)
	}

	rubies := strings.Split(string(buffer.Bytes()), "\n")

	for _, ruby := range rubies {
		if len(ruby) != 0 {
			rubyHome := fmt.Sprintf("%s/%s", rubiesHome, ruby)
			if _, err := os.Stat(rubyHome); err == nil {
				b.Put([]byte(ruby), []byte(rubyHome))
			} else {
				b.Put([]byte(ruby), make([]byte, 0))
			}
		}
	}

	if err := tx.Commit(); err != nil {
		fmt.Println("Cannot commit changes to rubies bucket")
		os.Exit(1)
	}

}

func install(c *cli.Context) {
	installCandidate := c.Args().Get(0)
	candidateDestDirectory := fmt.Sprintf("%s/%s", rubiesHome, installCandidate)

	if _, err := os.Stat(candidateDestDirectory); err == nil {
		fmt.Println("You already have installed:", installCandidate)
		os.Exit(1)
	}

	args := []string{installCandidate, candidateDestDirectory}

	cmd := exec.Command(fmt.Sprintf("%s/bin/ruby-build", rubyBuildDirectory), args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if err := cmd.Run(); err != nil {
		fmt.Println("Installtion failed")
		os.Exit(1)
	}

	updateAvailableRubies()
}
<commit_msg>List of rubies<commit_after>package main

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"strings"

	"github.com/boltdb/bolt"
	"github.com/codegangsta/cli"
)

const (
	rubyBuildRepo = "https://github.com/rbenv/ruby-build.git"
)

var currentHome = os.Getenv("HOME")
var grvmRuby = os.Getenv("grvm_ruby")
var grvmDirectory = fmt.Sprintf("%s/.grvm", currentHome)
var rubyBuildDirectory = fmt.Sprintf("%s/ruby-build", grvmDirectory)
var rubyBuildExecutable = fmt.Sprintf("%s/bin/ruby-build", rubyBuildDirectory)
var rubiesHome = fmt.Sprintf("%s/rubies", grvmDirectory)
var dbPath = fmt.Sprintf("%s/grvm.db", grvmDirectory)

func getDB() (*bolt.DB, error) {
	return bolt.Open(dbPath, 0600, nil)
}

func Print(c *cli.Context, args ...string) {
	if c.GlobalBool("shell") {
		fmt.Println(fmt.Sprintf("echo %q", strings.Join(args, " ")))
	} else {
		fmt.Println(strings.Join(args, " "))
	}
}

func main() {
	app := cli.NewApp()
	app.Name = "RVM"
	app.Usage = "RVM"
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name: "shell, s",
		},
	}
	app.Commands = []cli.Command{
		{
			Name:    "list",
			Aliases: []string{"l"},
			Usage:   "Show list installed rubies",
			Action:  list,
			Flags: []cli.Flag{
				cli.BoolFlag{
					Name: "known, k",
				},
			},
		},
		{
			Name:    "env",
			Aliases: []string{"e"},
			Usage:   "Show env for ruby version",
			Action:  env,
		},
		{
			Name:    "set",
			Aliases: []string{"s"},
			Usage:   "Set current ruby",
			Action:  set,
			Flags: []cli.Flag{
				cli.BoolFlag{
					Name: "default, d",
				},
			},
		},
		{
			Name:    "doctor",
			Aliases: []string{"d"},
			Usage:   "Fixes all bugs",
			Action:  doctor,
		},
		{
			Name:    "update",
			Aliases: []string{"u"},
			Usage:   "Updates available rubies",
			Action:  update,
		},
		{
			Name:    "install",
			Aliases: []string{"i"},
			Usage:   "Instqalls ruby",
			Action:  install,
		},
	}

	app.Run(os.Args)
}

func env(c *cli.Context) {
	var currentRuby string

	if len(grvmRuby) == 0 {
		currentRuby = getDefaultRuby(c)
	} else {
		currentRuby = grvmRuby
	}

	switch currentRuby {
	case "system":
		fmt.Println("export grvm_ruby=system")
	default:
		printEnv(currentRuby)
	}
}

func getDefaultRuby(c *cli.Context) string {
	db, err := getDB()
	if err != nil {
		Print(c, "Cannot open database file")
		os.Exit(1)
	}
	defer db.Close()

	tx, err := db.Begin(true)
	if err != nil {
		Print(c, "Cannpt open database transaction")
		os.Exit(1)
	}
	defer tx.Rollback()

	var b *bolt.Bucket
	var e error
	b, e = tx.CreateBucket([]byte("settings"))
	if e == bolt.ErrBucketExists {
		b = tx.Bucket([]byte("settings"))
	} else if e != nil {
		Print(c, "Cannot create bucket for settings")
		os.Exit(1)
	}

	defaultRuby := b.Get([]byte("default"))

	if defaultRuby == nil {
		return "system"
	} else if len(defaultRuby) == 0 {
		return "system"
	} else {
		candidate := string(defaultRuby)

		if err := checkCandidate(tx, candidate); err != nil {
			Print(c, err.Error())
			return "system"
		} else {
			return candidate
		}
	}
}

func printEnv(rubyVersion string) {
	currentPathEnv := os.Getenv("PATH")
	newPaths := rebuildPaths(currentPathEnv, currentHome)

	if rubyVersion == "system" {
		fmt.Println(fmt.Sprintf("export PATH=%s", newPaths))
	} else {
		gemsRoot := fmt.Sprintf("%s/gems/%s", grvmDirectory, rubyVersion)

		fmt.Println(fmt.Sprintf("export GEM_HOME=%s", gemsRoot))
		fmt.Println(fmt.Sprintf("export GEM_PATH=%s", gemsRoot))

		currentRubyBin := fmt.Sprintf("%s/%s/bin", rubiesHome, rubyVersion)
		currentGemsBin := fmt.Sprintf("%s/bin", gemsRoot)

		path := fmt.Sprintf("%s:%s:%s", currentRubyBin, currentGemsBin, newPaths)
		fmt.Println(fmt.Sprintf("export PATH=%s", path))
	}

	fmt.Println(fmt.Sprintf("export grvm_ruby=%s", rubyVersion))
}

func rebuildPaths(path, home string) string {
	var paths = strings.Split(path, ":")
	var currentPath = fmt.Sprintf("%s/%s", home, ".grvm")
	var newPaths []string

	for _, p := range paths {
		if !strings.HasPrefix(p, currentPath) {
			newPaths = append(newPaths, p)
		}
	}

	return strings.Join(newPaths, ":")

}

func list(c *cli.Context) {
	var installedRubies []string
	var knownRubies []string

	db, err := getDB()
	if err != nil {
		Print(c, "Cannot open database file:", dbPath)
		os.Exit(1)
	}
	defer db.Close()

	tx, err := db.Begin(false)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	defer tx.Rollback()

	b := tx.Bucket([]byte("rubies"))
	cursor := b.Cursor()

	for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
		if v != nil && len(v) != 0 {
			installedRubies = append(installedRubies, string(k))
		} else {
			knownRubies = append(knownRubies, string(k))
		}
	}

	fmt.Println("installed rubies:")
	for _, ruby := range installedRubies {
		fmt.Println("  ", ruby)
	}

	if c.Bool("known") {
		fmt.Println("known rubies:")
		for _, ruby := range knownRubies {
			fmt.Println("  ", ruby)
		}
	}
}

func doctor(c *cli.Context) {
	if _, err := os.Stat(rubyBuildDirectory); os.IsNotExist(err) {
		installRubyBuild()
	}

	updateAvailableRubies()
}

func installRubyBuild() {
	fmt.Println("Install ruby-build")
	args := []string{"clone", "https://github.com/rbenv/ruby-build.git", rubyBuildDirectory}

	cmd := exec.Command("git", args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if err := cmd.Run(); err != nil {
		fmt.Println("something going wrong, try to clone ruby-build manually: git", strings.Join(args, " "))
		os.Exit(1)
	}
}

func set(c *cli.Context) {
	db, err := getDB()
	if err != nil {
		Print(c, "Cannot open database file:", dbPath)
		os.Exit(1)
	}
	defer db.Close()

	tx, err := db.Begin(true)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	defer tx.Rollback()

	var b *bolt.Bucket
	var e error
	b, e = tx.CreateBucket([]byte("settings"))
	if e == bolt.ErrBucketExists {
		b = tx.Bucket([]byte("settings"))
	} else if e != nil {
		Print(c, "Cannot create bucket for settings")
		os.Exit(1)
	}

	candidate := c.Args().Get(0)

	if len(candidate) == 0 {
		Print(c, "No version given")
		os.Exit(1)
	}

	if err := checkCandidate(tx, candidate); err != nil {
		Print(c, err.Error())
		os.Exit(1)
	}

	if c.Bool("default") {
		b.Put([]byte("default"), []byte(candidate))

		if err := tx.Commit(); err != nil {
			fmt.Println("Cannot save settings")
			os.Exit(1)
		}

		printEnv(candidate)
		Print(c, "Now,", candidate, "default ruby")
	} else {
		printEnv(candidate)
	}
}

func checkCandidate(tx *bolt.Tx, candidate string) error {
	rubies := tx.Bucket([]byte("rubies"))
	value := rubies.Get([]byte(candidate))

	if value == nil {
		return fmt.Errorf("No candidate to set: %s", candidate)
	} else if len(value) == 0 {
		return fmt.Errorf("%s not installed, please use: grvm install %s", candidate, candidate)
	}

	return nil
}

func update(c *cli.Context) {
	if err := os.Chdir(rubyBuildDirectory); err != nil {
		fmt.Println("Cannot switch directory to:", rubyBuildDirectory)
		os.Exit(1)
	}

	args := []string{"pull", "origin", "master"}

	cmd := exec.Command("git", args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if err := cmd.Run(); err != nil {
		fmt.Println("something going wrong, try to update ruby-build manually: git", strings.Join(args, " "))
		os.Exit(1)
	}

	updateAvailableRubies()
}

func updateAvailableRubies() {
	db, err := getDB()
	if err != nil {
		fmt.Println("Cannot open database file:", dbPath)
		os.Exit(1)
	}
	defer db.Close()

	tx, err := db.Begin(true)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	defer tx.Rollback()

	var b *bolt.Bucket
	var e error
	b, e = tx.CreateBucket([]byte("rubies"))
	if e == bolt.ErrBucketExists {
		b = tx.Bucket([]byte("rubies"))
	} else if e != nil {
		fmt.Println(err)
		fmt.Println("Cannot create bucket for rubies")
		os.Exit(1)
	}

	buffer := bytes.NewBuffer(make([]byte, 0))

	cmd := exec.Command(rubyBuildExecutable, "--definitions")
	cmd.Stdout = buffer
	cmd.Stderr = buffer

	if err := cmd.Run(); err != nil {
		os.Exit(1)
	}

	rubies := strings.Split(string(buffer.Bytes()), "\n")

	for _, ruby := range rubies {
		if len(ruby) != 0 {
			rubyHome := fmt.Sprintf("%s/%s", rubiesHome, ruby)
			if _, err := os.Stat(rubyHome); err == nil {
				b.Put([]byte(ruby), []byte(rubyHome))
			} else {
				b.Put([]byte(ruby), make([]byte, 0))
			}
		}
	}

	if err := tx.Commit(); err != nil {
		fmt.Println("Cannot commit changes to rubies bucket")
		os.Exit(1)
	}

}

func install(c *cli.Context) {
	installCandidate := c.Args().Get(0)
	candidateDestDirectory := fmt.Sprintf("%s/%s", rubiesHome, installCandidate)

	if _, err := os.Stat(candidateDestDirectory); err == nil {
		fmt.Println("You already have installed:", installCandidate)
		os.Exit(1)
	}

	args := []string{installCandidate, candidateDestDirectory}

	cmd := exec.Command(fmt.Sprintf("%s/bin/ruby-build", rubyBuildDirectory), args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if err := cmd.Run(); err != nil {
		fmt.Println("Installtion failed")
		os.Exit(1)
	}

	updateAvailableRubies()
}
<|endoftext|>


<commit_before><commit_msg>syscall: add mmap test<commit_after><|endoftext|>


<commit_before>package shutdown

import (
	"net/http"
)

// WrapHandler will return an http Handler
// That will lock shutdown until all have completed
// and will return http.StatusServiceUnavailable if
// shutdown has been initiated.
func WrapHandler(h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		if !Lock() {
			w.WriteHeader(http.StatusServiceUnavailable)
		}
		h.ServeHTTP(w, r)
		Unlock()
	}
	return http.HandlerFunc(fn)
}
<commit_msg>Return if shutting down.<commit_after>package shutdown

import (
	"net/http"
)

// WrapHandler will return an http Handler
// That will lock shutdown until all have completed
// and will return http.StatusServiceUnavailable if
// shutdown has been initiated.
func WrapHandler(h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		if !Lock() {
			w.WriteHeader(http.StatusServiceUnavailable)
			return
		}
		h.ServeHTTP(w, r)
		Unlock()
	}
	return http.HandlerFunc(fn)
}
<|endoftext|>


<commit_before>package argot

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"regexp"
	"strings"

	"github.com/xeipuuv/gojsonschema"
)

// HttpCall captures all the state relating to a single HTTP call. It
// may be used multiple times. An HttpCall can only be used by a
// single go-routine at a time.
type HttpCall struct {
	// The client used to perform the request.
	Client *http.Client
	// The request to be made.
	Request *http.Request
	// The response.
	Response *http.Response
	// The body which once received can be repeatedly reused.
	ResponseBody []byte
}

// NewHttpCall creates a new HttpCall. If client is nil, a new
// http.Client is used.
func NewHttpCall(client *http.Client) *HttpCall {
	if client == nil {
		client = new(http.Client)
	}
	return &HttpCall{
		Client: client,
	}
}

// AssertNoRequest returns nil iff hc.Request is nil.
func (hc *HttpCall) AssertNoRequest() error {
	if hc.Request == nil {
		return nil
	} else {
		return errors.New("Request already set")
	}
}

// AssertRequest returns nil iff hc.Request is non-nil.
func (hc *HttpCall) AssertRequest() error {
	if hc.Request == nil {
		return errors.New("No Request set")
	} else {
		return nil
	}
}

// AssertNoResponse returns nil iff hc.Response is nil.
func (hc *HttpCall) AssertNoResponse() error {
	if hc.Response == nil {
		return nil
	} else {
		return errors.New("Response already set")
	}
}

// EnsureResponse is idempotent. If there is already a response then
// it will return nil. Otherwise if there is no Request then it will
// return non-nil. Otherwise it will use hc.Client.Do to perform the
// request, set hc.Response, and return any error that occurs.
//
// Always use this in any step where you want to inspect the
// hc.Response.
func (hc *HttpCall) EnsureResponse() error {
	if hc.Response != nil {
		return nil
	} else if hc.Request == nil {
		return errors.New("Cannot ensure response: no request.")
	} else if response, err := hc.Client.Do(hc.Request); err != nil {
		return fmt.Errorf("Error when making call of %v: %v", hc.Request, err)
	} else {
		hc.Response = response
		return nil
	}
}

// ReceiveBody is idempotent. It will ensure there is a response using
// hc.EnsureResponse. If there is already a non-nil hc.ResponseBody
// then it will return nil. Otherwise it will receive the
// Response.Body, store it in hc.ResponseBody, and return any error
// that occurs.
//
// Always use this in any step where you want to inspect the
// hc.ResponseBody.
func (hc *HttpCall) ReceiveBody() error {
	if err := hc.EnsureResponse(); err != nil {
		return err
	} else if hc.ResponseBody != nil {
		return nil
	} else {
		defer hc.Response.Body.Close()
		bites := new(bytes.Buffer)
		if _, err = io.Copy(bites, hc.Response.Body); err != nil {
			return err
		} else {
			hc.ResponseBody = bites.Bytes()
			return nil
		}
	}
}

// Reset is idempotent. You should ensure this is called at the end of
// life for each HttpCall. It drains Response bodies if necessary, and
// cleans up resources.
func (hc *HttpCall) Reset() error {
	hc.Request = nil
	if hc.Response != nil && hc.ResponseBody == nil {
		io.Copy(ioutil.Discard, hc.Response.Body)
		hc.Response.Body.Close()
	}
	hc.Response = nil
	hc.ResponseBody = nil
	return nil
}

// NewRequest is a Step that when executed will create a new request
// using the given parameters. The step will automatically call
// hc.Reset to tidy up any previous use of hc, and thus prepare hc for
// the new request.
func (hc *HttpCall) NewRequest(method, urlStr string, body io.Reader) Step {
	return NewNamedStep(fmt.Sprintf("NewRequest(%s: %s)", method, urlStr), func() error {
		if err := hc.Reset(); err != nil {
			return err
		} else if req, err := http.NewRequest(method, urlStr, body); err != nil {
			return err
		} else {
			hc.Request = req
			return nil
		}
	})
}

// RequestHeader is a Step that when executed will set the given key
// and value as a header on the HTTP Request. This can only be done
// after hc.Request has been created (with NewRequest), and before
// hc.Response has been created.
func (hc *HttpCall) RequestHeader(key, value string) Step {
	return NewNamedStep(fmt.Sprintf("RequestHeader(%s: %s)", key, value), func() error {
		if err := AnyError(hc.AssertRequest(), hc.AssertNoResponse()); err != nil {
			return err
		} else {
			hc.Request.Header.Set(key, value)
			return nil
		}
	})
}

// Call is a Step that when executed performs the HTTP Request
// Call. This is not normally necessary: all steps that require a
// Response will perform the HTTP Request when necessary. However, in
// some tests, you may not care about inspecting the HTTP Response but
// nevertheless wish the HTTP Request to be made.
func (hc *HttpCall) Call() Step {
	return NewNamedStep("Call", hc.EnsureResponse)
}

// ResponseStatusEquals is a Step that when executed ensures there is
// a non-nil hc.Response and errors unless the hc.Response.StatusCode
// equals the status parameter.
func (hc *HttpCall) ResponseStatusEquals(status int) Step {
	return NewNamedStep(fmt.Sprintf("ResponseStatusEquals(%d)", status), func() error {
		if err := hc.EnsureResponse(); err != nil {
			return err
		} else if hc.Response.StatusCode != status {
			return fmt.Errorf("Status: Expected %d; found %d.", status, hc.Response.StatusCode)
		} else {
			return nil
		}
	})
}

// ResponseHeaderExists is a Step that when executed ensures there is
// a non-nil hc.Response and errors unless hc.Response.Header[key]
// exists. It says nothing about the value of the header.
func (hc *HttpCall) ResponseHeaderExists(key string) Step {
	return NewNamedStep(fmt.Sprintf("ResponseHeaderExists(%s)", key), func() error {
		if err := hc.EnsureResponse(); err != nil {
			return err
		} else if _, found := hc.Response.Header[key]; !found {
			return fmt.Errorf("Header '%s' not found.", key)
		} else {
			return nil
		}
	})
}

// ResponseHeaderNotExists is a Step that when executed ensures there
// is a non-nil hc.Response and errors unless hc.Response.Header[key]
// does not exist.
func (hc *HttpCall) ResponseHeaderNotExists(key string) Step {
	return NewNamedStep(fmt.Sprintf("ResponseHeaderNotExists(%s)", key), func() error {
		if err := hc.EnsureResponse(); err != nil {
			return err
		} else if _, found := hc.Response.Header[key]; found {
			return fmt.Errorf("Header '%s' found.", key)
		} else {
			return nil
		}
	})
}

// ResponseHeaderEquals is a Step that when executed ensures there is
// a non-nil hc.Response and errors unless the
// hc.Response.Header.Get(key) equals the value parameter. Note this
// is an exact match.
func (hc *HttpCall) ResponseHeaderEquals(key, value string) Step {
	return NewNamedStep(fmt.Sprintf("ResponseHeaderEquals(%s: %s)", key, value), func() error {
		if err := hc.EnsureResponse(); err != nil {
			return err
		} else if header := hc.Response.Header.Get(key); header != value {
			return fmt.Errorf("Header '%s': Expected '%s'; found '%s'.", key, value, header)
		} else {
			return nil
		}
	})
}

// ResponseHeaderContains is a Step that when executed ensures there
// is a non-nil hc.Response and errors unless the
// hc.Response.Header.Get(key) contains the value parameter using
// strings.Contains.
func (hc *HttpCall) ResponseHeaderContains(key, value string) Step {
	return NewNamedStep(fmt.Sprintf("ResponseHeaderContains(%s: %s)", key, value), func() error {
		if err := hc.EnsureResponse(); err != nil {
			return err
		} else if header := hc.Response.Header.Get(key); !strings.Contains(header, value) {
			return fmt.Errorf("Header '%s': Expected '%s'; found '%s'.", key, value, header)
		} else {
			return nil
		}
	})
}

// ResponseBodyEquals is a Step that when executed ensures there is a
// non-nil hc.ResponseBody and errors unless the hc.ResponseBody
// equals the value parameter. Note this is an exact match.
func (hc *HttpCall) ResponseBodyEquals(value string) Step {
	return NewNamedStep("ResponseBodyEquals", func() error {
		if err := hc.ReceiveBody(); err != nil {
			return err
		} else if string(hc.ResponseBody) != value {
			return fmt.Errorf("Body: Expected '%s'; found '%s'.", value, string(hc.ResponseBody))
		} else {
			return nil
		}
	})
}

// ResponseBodyContains is a Step that when executed ensures there is
// a non-nil hc.ResponseBody and errors unless the hc.ResponseBody
// contains the value parameter using strings.Contains.
func (hc *HttpCall) ResponseBodyContains(value string) Step {
	return NewNamedStep("ResponseBodyContains", func() error {
		if err := hc.ReceiveBody(); err != nil {
			return err
		} else if !strings.Contains(string(hc.ResponseBody), value) {
			return fmt.Errorf("Body: Expected '%s'; found '%s'.", value, string(hc.ResponseBody))
		} else {
			return nil
		}
	})
}

// ResponseBodyMatches is a Step that when executed ensures there is
// a non-nil hc.ResponseBody and errors unless the hc.ResponseBody
// matches the regular expression parameter.
func (hc *HttpCall) ResponseBodyMatches(pattern *regexp.Regexp) Step {
	return NewNamedStep(fmt.Sprintf("ResponseBodyMatches(%v)", pattern), func() error {
		if err := hc.ReceiveBody(); err != nil {
			return err
		} else if !pattern.MatchString(string(hc.ResponseBody)) {
			return fmt.Errorf("Body: Expected to match the pattern '%v'; found '%s'.", pattern, string(hc.ResponseBody))
		} else {
			return nil
		}
	})
}

// ResponseBodyJSONSchema is a Step that when executed ensures there
// is a non-nil hc.ResponseBody and errors unless the hc.ResponseBody
// can be validated against the schema parameter using gojsonschema.
func (hc *HttpCall) ResponseBodyJSONSchema(schema string) Step {
	return NewNamedStep("ResponseBodyJSONSchema", func() error {
		if err := hc.ReceiveBody(); err != nil {
			return err
		} else {
			schemaLoader := gojsonschema.NewStringLoader(schema)
			bodyLoader := gojsonschema.NewStringLoader(string(hc.ResponseBody))
			if result, err := gojsonschema.Validate(schemaLoader, bodyLoader); err != nil {
				return err
			} else if !result.Valid() {
				msg := "Validation failure:\n"
				for _, err := range result.Errors() {
					msg += fmt.Sprintf("\t%v\n", err)
				}
				return errors.New(msg[:len(msg)-1])
			} else {
				return nil
			}
		}
	})
}
<commit_msg>Add better diff output for string comparison.<commit_after>package argot

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"regexp"
	"strings"

	"github.com/sergi/go-diff/diffmatchpatch"
	"github.com/xeipuuv/gojsonschema"
)

// HttpCall captures all the state relating to a single HTTP call. It
// may be used multiple times. An HttpCall can only be used by a
// single go-routine at a time.
type HttpCall struct {
	// The client used to perform the request.
	Client *http.Client
	// The request to be made.
	Request *http.Request
	// The response.
	Response *http.Response
	// The body which once received can be repeatedly reused.
	ResponseBody []byte
}

// NewHttpCall creates a new HttpCall. If client is nil, a new
// http.Client is used.
func NewHttpCall(client *http.Client) *HttpCall {
	if client == nil {
		client = new(http.Client)
	}
	return &HttpCall{
		Client: client,
	}
}

// AssertNoRequest returns nil iff hc.Request is nil.
func (hc *HttpCall) AssertNoRequest() error {
	if hc.Request == nil {
		return nil
	} else {
		return errors.New("Request already set")
	}
}

// AssertRequest returns nil iff hc.Request is non-nil.
func (hc *HttpCall) AssertRequest() error {
	if hc.Request == nil {
		return errors.New("No Request set")
	} else {
		return nil
	}
}

// AssertNoResponse returns nil iff hc.Response is nil.
func (hc *HttpCall) AssertNoResponse() error {
	if hc.Response == nil {
		return nil
	} else {
		return errors.New("Response already set")
	}
}

// EnsureResponse is idempotent. If there is already a response then
// it will return nil. Otherwise if there is no Request then it will
// return non-nil. Otherwise it will use hc.Client.Do to perform the
// request, set hc.Response, and return any error that occurs.
//
// Always use this in any step where you want to inspect the
// hc.Response.
func (hc *HttpCall) EnsureResponse() error {
	if hc.Response != nil {
		return nil
	} else if hc.Request == nil {
		return errors.New("Cannot ensure response: no request.")
	} else if response, err := hc.Client.Do(hc.Request); err != nil {
		return fmt.Errorf("Error when making call of %v: %v", hc.Request, err)
	} else {
		hc.Response = response
		return nil
	}
}

// ReceiveBody is idempotent. It will ensure there is a response using
// hc.EnsureResponse. If there is already a non-nil hc.ResponseBody
// then it will return nil. Otherwise it will receive the
// Response.Body, store it in hc.ResponseBody, and return any error
// that occurs.
//
// Always use this in any step where you want to inspect the
// hc.ResponseBody.
func (hc *HttpCall) ReceiveBody() error {
	if err := hc.EnsureResponse(); err != nil {
		return err
	} else if hc.ResponseBody != nil {
		return nil
	} else {
		defer hc.Response.Body.Close()
		bites := new(bytes.Buffer)
		if _, err = io.Copy(bites, hc.Response.Body); err != nil {
			return err
		} else {
			hc.ResponseBody = bites.Bytes()
			return nil
		}
	}
}

// Reset is idempotent. You should ensure this is called at the end of
// life for each HttpCall. It drains Response bodies if necessary, and
// cleans up resources.
func (hc *HttpCall) Reset() error {
	hc.Request = nil
	if hc.Response != nil && hc.ResponseBody == nil {
		io.Copy(ioutil.Discard, hc.Response.Body)
		hc.Response.Body.Close()
	}
	hc.Response = nil
	hc.ResponseBody = nil
	return nil
}

// NewRequest is a Step that when executed will create a new request
// using the given parameters. The step will automatically call
// hc.Reset to tidy up any previous use of hc, and thus prepare hc for
// the new request.
func (hc *HttpCall) NewRequest(method, urlStr string, body io.Reader) Step {
	return NewNamedStep(fmt.Sprintf("NewRequest(%s: %s)", method, urlStr), func() error {
		if err := hc.Reset(); err != nil {
			return err
		} else if req, err := http.NewRequest(method, urlStr, body); err != nil {
			return err
		} else {
			hc.Request = req
			return nil
		}
	})
}

// RequestHeader is a Step that when executed will set the given key
// and value as a header on the HTTP Request. This can only be done
// after hc.Request has been created (with NewRequest), and before
// hc.Response has been created.
func (hc *HttpCall) RequestHeader(key, value string) Step {
	return NewNamedStep(fmt.Sprintf("RequestHeader(%s: %s)", key, value), func() error {
		if err := AnyError(hc.AssertRequest(), hc.AssertNoResponse()); err != nil {
			return err
		} else {
			hc.Request.Header.Set(key, value)
			return nil
		}
	})
}

// Call is a Step that when executed performs the HTTP Request
// Call. This is not normally necessary: all steps that require a
// Response will perform the HTTP Request when necessary. However, in
// some tests, you may not care about inspecting the HTTP Response but
// nevertheless wish the HTTP Request to be made.
func (hc *HttpCall) Call() Step {
	return NewNamedStep("Call", hc.EnsureResponse)
}

// ResponseStatusEquals is a Step that when executed ensures there is
// a non-nil hc.Response and errors unless the hc.Response.StatusCode
// equals the status parameter.
func (hc *HttpCall) ResponseStatusEquals(status int) Step {
	return NewNamedStep(fmt.Sprintf("ResponseStatusEquals(%d)", status), func() error {
		if err := hc.EnsureResponse(); err != nil {
			return err
		} else if hc.Response.StatusCode != status {
			return fmt.Errorf("Status: Expected %d; found %d.", status, hc.Response.StatusCode)
		} else {
			return nil
		}
	})
}

// ResponseHeaderExists is a Step that when executed ensures there is
// a non-nil hc.Response and errors unless hc.Response.Header[key]
// exists. It says nothing about the value of the header.
func (hc *HttpCall) ResponseHeaderExists(key string) Step {
	return NewNamedStep(fmt.Sprintf("ResponseHeaderExists(%s)", key), func() error {
		if err := hc.EnsureResponse(); err != nil {
			return err
		} else if _, found := hc.Response.Header[key]; !found {
			return fmt.Errorf("Header '%s' not found.", key)
		} else {
			return nil
		}
	})
}

// ResponseHeaderNotExists is a Step that when executed ensures there
// is a non-nil hc.Response and errors unless hc.Response.Header[key]
// does not exist.
func (hc *HttpCall) ResponseHeaderNotExists(key string) Step {
	return NewNamedStep(fmt.Sprintf("ResponseHeaderNotExists(%s)", key), func() error {
		if err := hc.EnsureResponse(); err != nil {
			return err
		} else if _, found := hc.Response.Header[key]; found {
			return fmt.Errorf("Header '%s' found.", key)
		} else {
			return nil
		}
	})
}

// Diff two strings, output as coloured string, the expected parts will
// be removed/red if they're missing, the found/inserted parts will be
// green if present, if the parts are the same, no colour is applied.
func diff(expected string, got string) string {
	dmp := diffmatchpatch.New()
	diffs := dmp.DiffMain(expected, got, false)
	return dmp.DiffPrettyText(diffs)
}

// ResponseHeaderEquals is a Step that when executed ensures there is
// a non-nil hc.Response and errors unless the
// hc.Response.Header.Get(key) equals the value parameter. Note this
// is an exact match.
func (hc *HttpCall) ResponseHeaderEquals(key, value string) Step {
	return NewNamedStep(fmt.Sprintf("ResponseHeaderEquals(%s: %s)", key, value), func() error {
		if err := hc.EnsureResponse(); err != nil {
			return err
		} else if header := hc.Response.Header.Get(key); header != value {
			return fmt.Errorf("Header: '%s': Differed: '%s'.", key, diff(value, header))
		} else {
			return nil
		}
	})
}

// ResponseHeaderContains is a Step that when executed ensures there
// is a non-nil hc.Response and errors unless the
// hc.Response.Header.Get(key) contains the value parameter using
// strings.Contains.
func (hc *HttpCall) ResponseHeaderContains(key, value string) Step {
	return NewNamedStep(fmt.Sprintf("ResponseHeaderContains(%s: %s)", key, value), func() error {
		if err := hc.EnsureResponse(); err != nil {
			return err
		} else if header := hc.Response.Header.Get(key); !strings.Contains(header, value) {
			return fmt.Errorf("Header '%s': Expected '%s'; found '%s'.", key, value, header)
		} else {
			return nil
		}
	})
}

// ResponseBodyEquals is a Step that when executed ensures there is a
// non-nil hc.ResponseBody and errors unless the hc.ResponseBody
// equals the value parameter. Note this is an exact match.
func (hc *HttpCall) ResponseBodyEquals(value string) Step {
	return NewNamedStep("ResponseBodyEquals", func() error {
		if err := hc.ReceiveBody(); err != nil {
			return err
		} else if got := string(hc.ResponseBody); got != value {
			return fmt.Errorf("Body: Differed: '%s'.", diff(value, got))
		} else {
			return nil
		}
	})
}

// ResponseBodyContains is a Step that when executed ensures there is
// a non-nil hc.ResponseBody and errors unless the hc.ResponseBody
// contains the value parameter using strings.Contains.
func (hc *HttpCall) ResponseBodyContains(value string) Step {
	return NewNamedStep("ResponseBodyContains", func() error {
		if err := hc.ReceiveBody(); err != nil {
			return err
		} else if !strings.Contains(string(hc.ResponseBody), value) {
			return fmt.Errorf("Body: Expected '%s'; found '%s'.", value, string(hc.ResponseBody))
		} else {
			return nil
		}
	})
}

// ResponseBodyMatches is a Step that when executed ensures there is
// a non-nil hc.ResponseBody and errors unless the hc.ResponseBody
// matches the regular expression parameter.
func (hc *HttpCall) ResponseBodyMatches(pattern *regexp.Regexp) Step {
	return NewNamedStep(fmt.Sprintf("ResponseBodyMatches(%v)", pattern), func() error {
		if err := hc.ReceiveBody(); err != nil {
			return err
		} else if !pattern.MatchString(string(hc.ResponseBody)) {
			return fmt.Errorf("Body: Expected to match the pattern '%v'; found '%s'.", pattern, string(hc.ResponseBody))
		} else {
			return nil
		}
	})
}

// ResponseBodyJSONSchema is a Step that when executed ensures there
// is a non-nil hc.ResponseBody and errors unless the hc.ResponseBody
// can be validated against the schema parameter using gojsonschema.
func (hc *HttpCall) ResponseBodyJSONSchema(schema string) Step {
	return NewNamedStep("ResponseBodyJSONSchema", func() error {
		if err := hc.ReceiveBody(); err != nil {
			return err
		} else {
			schemaLoader := gojsonschema.NewStringLoader(schema)
			bodyLoader := gojsonschema.NewStringLoader(string(hc.ResponseBody))
			if result, err := gojsonschema.Validate(schemaLoader, bodyLoader); err != nil {
				return err
			} else if !result.Valid() {
				msg := "Validation failure:\n"
				for _, err := range result.Errors() {
					msg += fmt.Sprintf("\t%v\n", err)
				}
				return errors.New(msg[:len(msg)-1])
			} else {
				return nil
			}
		}
	})
}
<|endoftext|>


<commit_before>package conf

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"reflect"
	"sync"

	log "github.com/sirupsen/logrus"

	"github.com/Cepave/open-falcon-backend/modules/f2e-api/lambda_extends/utils"
	"github.com/spf13/viper"
)

type Gconfig struct {
	Funcations []FunConfig
}

type FunConfig struct {
	FuncationName string   `json:"function_name"`
	FilePath      string   `json:"file_path"`
	Params        []string `json:"params"`
	Description   string   `json:"description"`
	Codes         string   `json:"-"`
}

var (
	gconfig     []*FunConfig
	configLock  = new(sync.RWMutex)
	confpath    *string
	FunctionMap map[string]*FunConfig
)

func Config() map[string]*FunConfig {
	configLock.RLock()
	defer configLock.RUnlock()
	return FunctionMap
}

func functionMapGen() {
	currentPath := viper.GetString("lambda_extends.root_dir")
	possiblePath := []string{"lambda_extends/config/js", "lambda_extends/conf/js", "lambda_extends/js", "../config/js", "../js"}
	f := ""
	for _, pa := range possiblePath {
		paf := fmt.Sprintf("%s/%s", currentPath, pa)
		if _, err := os.Stat(paf); err != nil {
			log.Debugf("can't not load file from: %s", paf)
		} else {
			f = paf
			break
		}
	}
	if f == "" {
		log.Fatalf("load js files got error, currentPaht: %s , please check your code tree and make is correct!", currentPath)
	} else {
		log.Info("load javascript scrips successed in " + f)
	}

	FunctionMap = map[string]*FunConfig{}
	for _, v := range gconfig {
		contain := jsFileReader(fmt.Sprintf("%s/%s", f, v.FilePath))
		v.Codes = contain
		FunctionMap[v.FuncationName] = v
	}
}

func ReadConf() {
	currentPath := viper.GetString("lambda_extends.root_dir")
	possiblePath := []string{"lambda_extends/conf/lambdaSetup.json", "lambda_extends/config/lambdaSetup.json", "../config/lambdaSetup.json"}
	f := ""
	for _, pa := range possiblePath {
		paf := fmt.Sprintf("%s/%s", currentPath, pa)
		if _, err := os.Stat(paf); err != nil {
			log.Debugf("can't not load file from: %s", paf)
		} else {
			f = paf
			break
		}
	}
	if f == "" {
		log.Fatalf("lambdaSetup.json not found, currentPaht: %s", currentPath)
	} else {
		log.Info("read lambdaSetup.json successed wuth " + f)
	}

	confpath = &f
	dat, err := ioutil.ReadFile(f)
	if err != nil {
		log.Println(err)
	}
	var myconf []*FunConfig
	json.Unmarshal(dat, &myconf)
	if len(myconf) == 0 {
		log.Println("conf file is empty or format is wrong, please check it!")
	}
	gconfig = myconf
	functionMapGen()
}

func Reload() {
	configLock.RLock()
	ReadConf()
	defer configLock.RUnlock()
}

func GetFunc(key string) *FunConfig {
	return FunctionMap[key]
}

func GetAvaibleFun() []string {
	return utils.GetMapKeys(reflect.ValueOf(FunctionMap).MapKeys())
}
<commit_msg>fix read conf issue of f2e-api lambda web<commit_after>package conf

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"reflect"
	"sync"

	log "github.com/sirupsen/logrus"

	"github.com/Cepave/open-falcon-backend/modules/f2e-api/lambda_extends/utils"
	"github.com/spf13/viper"
)

type Gconfig struct {
	Funcations []FunConfig
}

type FunConfig struct {
	FuncationName string   `json:"function_name"`
	FilePath      string   `json:"file_path"`
	Params        []string `json:"params"`
	Description   string   `json:"description"`
	Codes         string   `json:"-"`
}

var (
	gconfig     []*FunConfig
	configLock  = new(sync.RWMutex)
	confpath    *string
	FunctionMap map[string]*FunConfig
)

func Config() map[string]*FunConfig {
	configLock.RLock()
	defer configLock.RUnlock()
	return FunctionMap
}

func functionMapGen() {
	currentPath := viper.GetString("lambda_extends.root_dir")
	possiblePath := []string{"lambda_extends/config/js", "lambda_extends/conf/js", "lambda_extends/js", "../config/js", "../js", "f2e-api/bin"}
	f := ""
	for _, pa := range possiblePath {
		paf := fmt.Sprintf("%s/%s", currentPath, pa)
		if _, err := os.Stat(paf); err != nil {
			log.Debugf("can't not load file from: %s", paf)
		} else {
			f = paf
			break
		}
	}
	if f == "" {
		log.Fatalf("load js files got error, currentPaht: %s , please check your code tree and make is correct!", currentPath)
	} else {
		log.Info("load javascript scrips successed in " + f)
	}

	FunctionMap = map[string]*FunConfig{}
	for _, v := range gconfig {
		contain := jsFileReader(fmt.Sprintf("%s/%s", f, v.FilePath))
		v.Codes = contain
		FunctionMap[v.FuncationName] = v
	}
}

func ReadConf() {
	currentPath := viper.GetString("lambda_extends.root_dir")
	possiblePath := []string{"lambda_extends/conf/lambdaSetup.json", "lambda_extends/config/lambdaSetup.json", "../config/lambdaSetup.json", "f2e-api/config/lambdaSetup.json"}
	f := ""
	for _, pa := range possiblePath {
		paf := fmt.Sprintf("%s/%s", currentPath, pa)
		if _, err := os.Stat(paf); err != nil {
			log.Debugf("can't not load file from: %s", paf)
		} else {
			f = paf
			break
		}
	}
	if f == "" {
		log.Fatalf("lambdaSetup.json not found, currentPaht: %s", currentPath)
	} else {
		log.Info("read lambdaSetup.json successed wuth " + f)
	}

	confpath = &f
	dat, err := ioutil.ReadFile(f)
	if err != nil {
		log.Println(err)
	}
	var myconf []*FunConfig
	json.Unmarshal(dat, &myconf)
	if len(myconf) == 0 {
		log.Println("conf file is empty or format is wrong, please check it!")
	}
	gconfig = myconf
	functionMapGen()
}

func Reload() {
	configLock.RLock()
	ReadConf()
	defer configLock.RUnlock()
}

func GetFunc(key string) *FunConfig {
	return FunctionMap[key]
}

func GetAvaibleFun() []string {
	return utils.GetMapKeys(reflect.ValueOf(FunctionMap).MapKeys())
}
<|endoftext|>


<commit_before>package pygo

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
)

const (
	code = "import pygo; pygo.run('%s')"
)

var (
	PythonBinary string = "python2.7"
	defaultOpts  PyOpts
)

type response struct {
	value interface{}
	err   error
}

type call struct {
	function string
	args     []interface{}
	kwargs   map[string]interface{}
	response chan *response
}

type pygoImpl struct {
	binPath string
	module  string
	opts    *PyOpts
	ps      *os.Process

	stream  Stream
	chanerr *os.File

	//only filled if process exited.
	stderr string
	state  *os.ProcessState

	channel chan *call
}

type PyOpts struct {
	PythonPath string
}

func NewPy(module string, opts *PyOpts) (Pygo, error) {
	if opts == nil {
		opts = &defaultOpts
	}

	path, err := exec.LookPath(PythonBinary)

	if err != nil {
		return nil, err
	}

	py := &pygoImpl{
		binPath: path,
		opts:    opts,
		module:  module,
		channel: make(chan *call),
	}

	err = py.init()
	if err != nil {
		return nil, err
	}

	go py.wait()
	go py.process()

	return py, nil
}

func (py *pygoImpl) wait() {
	data, err := ioutil.ReadAll(py.chanerr)
	if err != nil {
		log.Println(err)
	}

	py.stderr = string(data)

	state, _ := py.ps.Wait()
	py.state = state
}

//init opes the pipes and start the python process.
func (py *pygoImpl) init() error {
	stderrReader, stderrWriter, err := os.Pipe()

	if err != nil {
		return err
	}

	pyIn, goOut, err := os.Pipe()
	if err != nil {
		return err
	}

	goIn, pyOut, err := os.Pipe()
	if err != nil {
		return err
	}

	var env []string = nil

	if py.opts.PythonPath != "" {
		env = []string{fmt.Sprintf("PYTHONPATH=%s", py.opts.PythonPath)}
	}

	attr := &os.ProcAttr{
		Files: []*os.File{nil, nil, stderrWriter, pyIn, pyOut},
		Env:   env,
	}

	ps, err := os.StartProcess(py.binPath, []string{
		PythonBinary,
		"-c",
		fmt.Sprintf(code, py.module)},
		attr)

	if err != nil {
		return err
	}

	py.ps = ps
	py.stream = NewStream(goOut, goIn)
	py.chanerr = stderrReader

	return nil
}

func (py *pygoImpl) Error() string {
	return py.stderr
}

func (py *pygoImpl) processSingle() {
	c := <-py.channel

	var response response

	defer func() {
		c.response <- &response
	}()

	data := map[string]interface{}{
		"function": c.function,
		"args":     c.args,
		"kwargs":   c.kwargs,
	}

	err := py.stream.Write(data)
	if err != nil {
		response.err = err
		return
	}
	//read response.
	value, err := py.stream.Read()

	response.value = value
	response.err = err
}

func (py *pygoImpl) process() {
	for {
		py.processSingle()
	}
}

func (py *pygoImpl) call(function string, args []interface{}, kwargs map[string]interface{}) (interface{}, error) {
	if py.state != nil {
		return nil, fmt.Errorf("Can't execute python code, python process has exited", py.stderr)
	}

	responseChan := make(chan *response)
	defer close(responseChan)

	call := call{
		function: function,
		args:     args,
		kwargs:   kwargs,
		response: responseChan,
	}
	py.channel <- &call
	response := <-responseChan
	if response.err != nil {
		return nil, response.err
	}
	responseMap := response.value.(map[string]interface{})

	if state, ok := responseMap["state"]; ok {
		if state.(string) == "ERROR" {
			return nil, fmt.Errorf("%v", responseMap["return"])
		}
	}

	return responseMap["return"], nil
}

func (py *pygoImpl) Apply(function string, kwargs map[string]interface{}) (interface{}, error) {
	return py.call(function, nil, kwargs)
}

func (py *pygoImpl) Call(function string, args ...interface{}) (interface{}, error) {
	return py.call(function, args, nil)
}
<commit_msg>Support extra env variables<commit_after>package pygo

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
)

const (
	code = "import pygo; pygo.run('%s')"
)

var (
	PythonBinary string = "python2.7"
	defaultOpts  PyOpts
)

type response struct {
	value interface{}
	err   error
}

type call struct {
	function string
	args     []interface{}
	kwargs   map[string]interface{}
	response chan *response
}

type pygoImpl struct {
	binPath string
	module  string
	opts    *PyOpts
	ps      *os.Process

	stream  Stream
	chanerr *os.File

	//only filled if process exited.
	stderr string
	state  *os.ProcessState

	channel chan *call
}

type PyOpts struct {
	PythonPath string
	Env        []string
}

func NewPy(module string, opts *PyOpts) (Pygo, error) {
	if opts == nil {
		opts = &defaultOpts
	}

	path, err := exec.LookPath(PythonBinary)

	if err != nil {
		return nil, err
	}

	py := &pygoImpl{
		binPath: path,
		opts:    opts,
		module:  module,
		channel: make(chan *call),
	}

	err = py.init()
	if err != nil {
		return nil, err
	}

	go py.wait()
	go py.process()

	return py, nil
}

func (py *pygoImpl) wait() {
	data, err := ioutil.ReadAll(py.chanerr)
	if err != nil {
		log.Println(err)
	}

	py.stderr = string(data)

	state, _ := py.ps.Wait()
	py.state = state
}

//init opes the pipes and start the python process.
func (py *pygoImpl) init() error {
	stderrReader, stderrWriter, err := os.Pipe()

	if err != nil {
		return err
	}

	pyIn, goOut, err := os.Pipe()
	if err != nil {
		return err
	}

	goIn, pyOut, err := os.Pipe()
	if err != nil {
		return err
	}

	var env []string = nil

	if py.opts.PythonPath != "" {
		env = []string{fmt.Sprintf("PYTHONPATH=%s", py.opts.PythonPath)}
	}

	env = append(env, py.opts.Env...)

	attr := &os.ProcAttr{
		Files: []*os.File{nil, nil, stderrWriter, pyIn, pyOut},
		Env:   env,
	}

	ps, err := os.StartProcess(py.binPath, []string{
		PythonBinary,
		"-c",
		fmt.Sprintf(code, py.module)},
		attr)

	if err != nil {
		return err
	}

	py.ps = ps
	py.stream = NewStream(goOut, goIn)
	py.chanerr = stderrReader

	return nil
}

func (py *pygoImpl) Error() string {
	return py.stderr
}

func (py *pygoImpl) processSingle() {
	c := <-py.channel

	var response response

	defer func() {
		c.response <- &response
	}()

	data := map[string]interface{}{
		"function": c.function,
		"args":     c.args,
		"kwargs":   c.kwargs,
	}

	err := py.stream.Write(data)
	if err != nil {
		response.err = err
		return
	}
	//read response.
	value, err := py.stream.Read()

	response.value = value
	response.err = err
}

func (py *pygoImpl) process() {
	for {
		py.processSingle()
	}
}

func (py *pygoImpl) call(function string, args []interface{}, kwargs map[string]interface{}) (interface{}, error) {
	if py.state != nil {
		return nil, fmt.Errorf("Can't execute python code, python process has exited", py.stderr)
	}

	responseChan := make(chan *response)
	defer close(responseChan)

	call := call{
		function: function,
		args:     args,
		kwargs:   kwargs,
		response: responseChan,
	}
	py.channel <- &call
	response := <-responseChan
	if response.err != nil {
		return nil, response.err
	}
	responseMap := response.value.(map[string]interface{})

	if state, ok := responseMap["state"]; ok {
		if state.(string) == "ERROR" {
			return nil, fmt.Errorf("%v", responseMap["return"])
		}
	}

	return responseMap["return"], nil
}

func (py *pygoImpl) Apply(function string, kwargs map[string]interface{}) (interface{}, error) {
	return py.call(function, nil, kwargs)
}

func (py *pygoImpl) Call(function string, args ...interface{}) (interface{}, error) {
	return py.call(function, args, nil)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"runtime"

	"github.com/kardianos/osext"
)

var cmdInfo = &Command{
	Exec:        runInfo,
	UsageLine:   "info",
	Description: "Display system-wide information",
	Help:        "Display system-wide information.",
}

func runInfo(cmd *Command, args []string) {
	if len(args) != 0 {
		fmt.Fprintf(os.Stderr, "usage: scw %s\n", cmd.UsageLine)
		os.Exit(1)
	}

	// FIXME: fmt.Printf("Servers: %s\n", "quantity")
	// FIXME: fmt.Printf("Images: %s\n", "quantity")
	fmt.Printf("Debug mode (client): %v\n", os.Getenv("DEBUG") != "")

	fmt.Printf("Organization: %s\n", config.Organization)
	// FIXME: add partially-masked token
	fmt.Printf("API Endpoint: %s\n", os.Getenv("scaleway_api_endpoint"))
	configPath, _ := GetConfigFilePath()
	fmt.Printf("RC file: %s\n", configPath)
	fmt.Printf("User: %s\n", os.Getenv("USER"))
	fmt.Printf("CPUs: %d\n", runtime.NumCPU())
	hostname, _ := os.Hostname()
	fmt.Printf("Hostname: %s\n", hostname)
	cliPath, _ := osext.Executable()
	fmt.Printf("CLI Path: %s\n", cliPath)

	// FIXME: Cache information
}
<commit_msg>Added information about the cache in 'scw info'. #16<commit_after>package main

import (
	"fmt"
	"os"
	"runtime"

	"github.com/kardianos/osext"
)

var cmdInfo = &Command{
	Exec:        runInfo,
	UsageLine:   "info",
	Description: "Display system-wide information",
	Help:        "Display system-wide information.",
}

func runInfo(cmd *Command, args []string) {
	if len(args) != 0 {
		fmt.Fprintf(os.Stderr, "usage: scw %s\n", cmd.UsageLine)
		os.Exit(1)
	}

	// FIXME: fmt.Printf("Servers: %s\n", "quantity")
	// FIXME: fmt.Printf("Images: %s\n", "quantity")
	fmt.Printf("Debug mode (client): %v\n", os.Getenv("DEBUG") != "")

	fmt.Printf("Organization: %s\n", config.Organization)
	// FIXME: add partially-masked token
	fmt.Printf("API Endpoint: %s\n", os.Getenv("scaleway_api_endpoint"))
	configPath, _ := GetConfigFilePath()
	fmt.Printf("RC file: %s\n", configPath)
	fmt.Printf("User: %s\n", os.Getenv("USER"))
	fmt.Printf("CPUs: %d\n", runtime.NumCPU())
	hostname, _ := os.Hostname()
	fmt.Printf("Hostname: %s\n", hostname)
	cliPath, _ := osext.Executable()
	fmt.Printf("CLI Path: %s\n", cliPath)

	fmt.Printf("CachedServers: %d\n", len(cmd.API.Cache.Servers))
	fmt.Printf("CachedImages: %d\n", len(cmd.API.Cache.Images))
}
<|endoftext|>


<commit_before>package apidApigeeSync

import (
	"encoding/json"
	"fmt"
	"github.com/30x/apid"
	"os"
)

const (
	configPollInterval        = "apigeesync_poll_interval"
	configProxyServerBaseURI  = "apigeesync_proxy_server_base"
	configSnapServerBaseURI   = "apigeesync_snapshot_server_base"
	configChangeServerBaseURI = "apigeesync_change_server_base"
	configConsumerKey         = "apigeesync_consumer_key"
	configConsumerSecret      = "apigeesync_consumer_secret"
	configApidClusterId       = "apigeesync_cluster_id"
	configSnapshotProtocol    = "apigeesync_snapshot_proto"
	configName                = "apigeesync_instance_name"
	ApigeeSyncEventSelector   = "ApigeeSync"

	// special value - set by ApigeeSync, not taken from configuration
	configApidInstanceID = "apigeesync_apid_instance_id"
	// This will not be needed once we have plugin
	// handling tokens.
	bearerToken = "apigeesync_bearer_token"
)

var (
	log               apid.LogService
	config            apid.ConfigService
	data              apid.DataService
	events            apid.EventsService
	apidInfo          apidInstanceInfo
	apidPluginDetails string
)

type apidInstanceInfo struct {
	InstanceID, InstanceName, ClusterID, LastSnapshot string
}

type pluginDetail struct {
	Name          string `json:"name"`
	SchemaVersion string `json:"schemaVer"`
}

func init() {
	apid.RegisterPlugin(initPlugin)
}

func initDefaults() {
	config.SetDefault(configPollInterval, 120)
	name, errh := os.Hostname()
	if (errh != nil) && (len(config.GetString(configName)) == 0) {
		log.Errorf("Not able to get hostname for kernel. Please set '%s' property in config", configName)
		name = "Undefined"
	}
	config.SetDefault(configName, name)
	log.Debugf("Using %s as display name", config.GetString(configName))
}

func SetLogger(logger apid.LogService) {
	log = logger
}

func initPlugin(services apid.Services) (apid.PluginData, error) {
	SetLogger(services.Log().ForModule("apigeeSync"))
	log.Debug("start init")

	config = services.Config()
	initDefaults()

	data = services.Data()
	events = services.Events()

	/* This callback function will get called, once all the plugins are
	 * initialized (not just this plugin). This is needed because,
	 * downloadSnapshots/changes etc have to begin to be processed only
	 * after all the plugins are initialized
	 */
	events.ListenFunc(apid.SystemEventsSelector, postInitPlugins)

	// check for required values
	for _, key := range []string{configProxyServerBaseURI, configConsumerKey, configConsumerSecret,
		configSnapServerBaseURI, configChangeServerBaseURI} {
		if !config.IsSet(key) {
			return pluginData, fmt.Errorf("Missing required config value: %s", key)
		}
	}

	// set up default database
	db, err := data.DB()
	if err != nil {
		return pluginData, fmt.Errorf("Unable to access DB: %v", err)
	}
	err = initDB(db)
	if err != nil {
		return pluginData, fmt.Errorf("Unable to access DB: %v", err)
	}
	setDB(db)

	apidInfo, err = getApidInstanceInfo()
	if err != nil {
		return pluginData, fmt.Errorf("Unable to get apid instance info: %v", err)
	}

	if config.IsSet(configApidInstanceID) {
		log.Warnf("ApigeeSync plugin overriding %s.", configApidInstanceID)
	}
	config.Set(configApidInstanceID, apidInfo.InstanceID)

	log.Debug("end init")

	return pluginData, nil
}

// Plugins have all initialized, gather their info and start the ApigeeSync downloads
func postInitPlugins(event apid.Event) {
	var plinfoDetails []pluginDetail
	if pie, ok := event.(apid.PluginsInitializedEvent); ok {
		/*
		 * Store the plugin details in the heap. Needed during
		 * Bearer token generation request.
		 */
		for _, plugin := range pie.Plugins {
			name := plugin.Name
			version := plugin.Version
			if schemaVersion, ok := plugin.ExtraData["schemaVersion"].(string); ok {
				inf := pluginDetail{
					Name:          name,
					SchemaVersion: schemaVersion}
				plinfoDetails = append(plinfoDetails, inf)
				log.Debugf("plugin %s is version %s, schemaVersion: %s", name, version, schemaVersion)
			}
		}
		if plinfoDetails == nil {
			log.Panicf("No Plugins registered!")
		}

		pgInfo, err := json.Marshal(plinfoDetails)
		if err != nil {
			log.Panicf("Unable to marshal plugin data: %v", err)
		}
		apidPluginDetails = string(pgInfo[:])

		log.Debug("start post plugin init")

		go bootstrap()

		events.Listen(ApigeeSyncEventSelector, &handler{})
		log.Debug("Done post plugin init")
	}
}
<commit_msg>make json default protocol<commit_after>package apidApigeeSync

import (
	"encoding/json"
	"fmt"
	"os"

	"github.com/30x/apid"
)

const (
	configPollInterval        = "apigeesync_poll_interval"
	configProxyServerBaseURI  = "apigeesync_proxy_server_base"
	configSnapServerBaseURI   = "apigeesync_snapshot_server_base"
	configChangeServerBaseURI = "apigeesync_change_server_base"
	configConsumerKey         = "apigeesync_consumer_key"
	configConsumerSecret      = "apigeesync_consumer_secret"
	configApidClusterId       = "apigeesync_cluster_id"
	configSnapshotProtocol    = "apigeesync_snapshot_proto"
	configName                = "apigeesync_instance_name"
	ApigeeSyncEventSelector   = "ApigeeSync"

	// special value - set by ApigeeSync, not taken from configuration
	configApidInstanceID = "apigeesync_apid_instance_id"
	// This will not be needed once we have plugin
	// handling tokens.
	bearerToken = "apigeesync_bearer_token"
)

var (
	log               apid.LogService
	config            apid.ConfigService
	data              apid.DataService
	events            apid.EventsService
	apidInfo          apidInstanceInfo
	apidPluginDetails string
)

type apidInstanceInfo struct {
	InstanceID, InstanceName, ClusterID, LastSnapshot string
}

type pluginDetail struct {
	Name          string `json:"name"`
	SchemaVersion string `json:"schemaVer"`
}

func init() {
	apid.RegisterPlugin(initPlugin)
}

func initDefaults() {
	config.SetDefault(configPollInterval, 120)
	config.SetDefault(configSnapshotProtocol, "json")
	name, errh := os.Hostname()
	if (errh != nil) && (len(config.GetString(configName)) == 0) {
		log.Errorf("Not able to get hostname for kernel. Please set '%s' property in config", configName)
		name = "Undefined"
	}
	config.SetDefault(configName, name)
	log.Debugf("Using %s as display name", config.GetString(configName))
}

func SetLogger(logger apid.LogService) {
	log = logger
}

func initPlugin(services apid.Services) (apid.PluginData, error) {
	SetLogger(services.Log().ForModule("apigeeSync"))
	log.Debug("start init")

	config = services.Config()
	initDefaults()

	data = services.Data()
	events = services.Events()

	/* This callback function will get called, once all the plugins are
	 * initialized (not just this plugin). This is needed because,
	 * downloadSnapshots/changes etc have to begin to be processed only
	 * after all the plugins are initialized
	 */
	events.ListenFunc(apid.SystemEventsSelector, postInitPlugins)

	// check for required values
	for _, key := range []string{configProxyServerBaseURI, configConsumerKey, configConsumerSecret,
		configSnapServerBaseURI, configChangeServerBaseURI} {
		if !config.IsSet(key) {
			return pluginData, fmt.Errorf("Missing required config value: %s", key)
		}
	}
	proto := config.GetString(configSnapshotProtocol)
	if proto != "json" && proto != "proto" {
		return pluginData, fmt.Errorf("Illegal value for %s. Must be: 'json' or 'proto'", configSnapshotProtocol)
	}

	// set up default database
	db, err := data.DB()
	if err != nil {
		return pluginData, fmt.Errorf("Unable to access DB: %v", err)
	}
	err = initDB(db)
	if err != nil {
		return pluginData, fmt.Errorf("Unable to access DB: %v", err)
	}
	setDB(db)

	apidInfo, err = getApidInstanceInfo()
	if err != nil {
		return pluginData, fmt.Errorf("Unable to get apid instance info: %v", err)
	}

	if config.IsSet(configApidInstanceID) {
		log.Warnf("ApigeeSync plugin overriding %s.", configApidInstanceID)
	}
	config.Set(configApidInstanceID, apidInfo.InstanceID)

	log.Debug("end init")

	return pluginData, nil
}

// Plugins have all initialized, gather their info and start the ApigeeSync downloads
func postInitPlugins(event apid.Event) {
	var plinfoDetails []pluginDetail
	if pie, ok := event.(apid.PluginsInitializedEvent); ok {
		/*
		 * Store the plugin details in the heap. Needed during
		 * Bearer token generation request.
		 */
		for _, plugin := range pie.Plugins {
			name := plugin.Name
			version := plugin.Version
			if schemaVersion, ok := plugin.ExtraData["schemaVersion"].(string); ok {
				inf := pluginDetail{
					Name:          name,
					SchemaVersion: schemaVersion}
				plinfoDetails = append(plinfoDetails, inf)
				log.Debugf("plugin %s is version %s, schemaVersion: %s", name, version, schemaVersion)
			}
		}
		if plinfoDetails == nil {
			log.Panicf("No Plugins registered!")
		}

		pgInfo, err := json.Marshal(plinfoDetails)
		if err != nil {
			log.Panicf("Unable to marshal plugin data: %v", err)
		}
		apidPluginDetails = string(pgInfo[:])

		log.Debug("start post plugin init")

		go bootstrap()

		events.Listen(ApigeeSyncEventSelector, &handler{})
		log.Debug("Done post plugin init")
	}
}
<|endoftext|>


<commit_before>package apidApigeeSync

import (
	"database/sql"
	"fmt"
	"github.com/30x/apid"
)

const (
	configPollInterval        = "apigeesync_poll_interval"
	configProxyServerBaseURI  = "apigeesync_proxy_server_base"
	configSnapServerBaseURI   = "apigeesync_snapshot_server_base"
	configChangeServerBaseURI = "apigeesync_change_server_base"
	configConsumerKey         = "apigeesync_consumer_key"
	configConsumerSecret      = "apigeesync_consumer_secret"
	configScopeId             = "apigeesync_bootstrap_id"
	configSnapshotProtocol    = "apigeesync_snapshot_proto"
	configUnitTestMode        = "apigeesync_UnitTest_mode"
	ApigeeSyncEventSelector   = "ApigeeSync"
)

var (
	log    apid.LogService
	config apid.ConfigService
	data   apid.DataService
	events apid.EventsService
)

func init() {
	apid.RegisterPlugin(initPlugin)
	apid.RegisterPostPlugin(postinitPlugin)
}

func postinitPlugin(services apid.Services) error {

	log.Debug("start post plugin init")
	/* call to Download Snapshot info */
	go DownloadSnapshot()

	/* Begin Looking for changes periodically */
	log.Debug("starting update goroutine")
	go updatePeriodicChanges()

	events.Listen(ApigeeSyncEventSelector, &handler{})
	log.Debug("Done post plugin init")
	return nil

}

func initPlugin(services apid.Services) error {
	log = services.Log().ForModule("apigeeSync")
	log.Debug("start init")

	config = services.Config()
	data = services.Data()
	events = services.Events()

	config.SetDefault(configPollInterval, 120)

	db, err := data.DB()
	if err != nil {
		log.Panic("Unable to access DB", err)
	}

	// check for required values
	for _, key := range []string{configProxyServerBaseURI, configConsumerKey, configConsumerSecret, configSnapServerBaseURI, configChangeServerBaseURI} {
		if !config.IsSet(key) {
			return fmt.Errorf("Missing required config value: %s", key)
		}
	}

	var count int
	row := db.QueryRow("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='apid_config' COLLATE NOCASE;")
	if err := row.Scan(&count); err != nil {
		log.Panic("Unable to setup database", err)
	}
	if count == 0 {
		createTables(db)
	}

	log.Debug("end init")

	return nil
}

func createTables(db *sql.DB) {
	_, err := db.Exec(`
CREATE TABLE apid_config (
    id text,
    name text,
    description text,
    umbrella_org_app_name text,
    created int64,
    created_by text,
    updated int64,
    updated_by text,
    _apid_scope text,
    snapshotInfo text,
    PRIMARY KEY (id)
);
CREATE TABLE apid_config_scope (
    id text,
    apid_config_id text,
    scope text,
    created int64,
    created_by text,
    updated int64,
    updated_by text,
    _apid_scope text,
    PRIMARY KEY (id)
);
`)
	if err != nil {
		log.Panic("Unable to initialize DB", err)
	}
}
<commit_msg>Fix initialization to use apid events instead of a new plugin callback<commit_after>package apidApigeeSync

import (
	"database/sql"
	"fmt"
	"github.com/30x/apid"
)

const (
	configPollInterval        = "apigeesync_poll_interval"
	configProxyServerBaseURI  = "apigeesync_proxy_server_base"
	configSnapServerBaseURI   = "apigeesync_snapshot_server_base"
	configChangeServerBaseURI = "apigeesync_change_server_base"
	configConsumerKey         = "apigeesync_consumer_key"
	configConsumerSecret      = "apigeesync_consumer_secret"
	configScopeId             = "apigeesync_bootstrap_id"
	configSnapshotProtocol    = "apigeesync_snapshot_proto"
	configUnitTestMode        = "apigeesync_UnitTest_mode"
	ApigeeSyncEventSelector   = "ApigeeSync"
)

var (
	log    apid.LogService
	config apid.ConfigService
	data   apid.DataService
	events apid.EventsService
)

func init() {
	apid.RegisterPlugin(initPlugin)
}

func postInitPlugins() {

	log.Debug("start post plugin init")
	/* call to Download Snapshot info */
	go DownloadSnapshot()

	/* Begin Looking for changes periodically */
	log.Debug("starting update goroutine")
	go updatePeriodicChanges()

	events.Listen(ApigeeSyncEventSelector, &handler{})
	log.Debug("Done post plugin init")
}

func initPlugin(services apid.Services) error {
	log = services.Log().ForModule("apigeeSync")
	log.Debug("start init")

	config = services.Config()
	data = services.Data()
	events = services.Events()

	events.Listen(apid.PluginsInitializedEvent, postInitPlugins)

	config.SetDefault(configPollInterval, 120)

	db, err := data.DB()
	if err != nil {
		log.Panic("Unable to access DB", err)
	}

	// check for required values
	for _, key := range []string{configProxyServerBaseURI, configConsumerKey, configConsumerSecret, configSnapServerBaseURI, configChangeServerBaseURI} {
		if !config.IsSet(key) {
			return fmt.Errorf("Missing required config value: %s", key)
		}
	}

	var count int
	row := db.QueryRow("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='apid_config' COLLATE NOCASE;")
	if err := row.Scan(&count); err != nil {
		log.Panic("Unable to setup database", err)
	}
	if count == 0 {
		createTables(db)
	}

	log.Debug("end init")

	return nil
}

func createTables(db *sql.DB) {
	_, err := db.Exec(`
CREATE TABLE apid_config (
    id text,
    name text,
    description text,
    umbrella_org_app_name text,
    created int64,
    created_by text,
    updated int64,
    updated_by text,
    _apid_scope text,
    snapshotInfo text,
    PRIMARY KEY (id)
);
CREATE TABLE apid_config_scope (
    id text,
    apid_config_id text,
    scope text,
    created int64,
    created_by text,
    updated int64,
    updated_by text,
    _apid_scope text,
    PRIMARY KEY (id)
);
`)
	if err != nil {
		log.Panic("Unable to initialize DB", err)
	}
}
<|endoftext|>