<commit_before>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"
	"sync"

	"github.com/BurntSushi/toml"
	"github.com/k0pernicus/goyave/configurationFile"
	"github.com/k0pernicus/goyave/consts"
	"github.com/k0pernicus/goyave/traces"
	"github.com/k0pernicus/goyave/utils"
	"github.com/k0pernicus/goyave/walk"
	"github.com/spf13/cobra"
)

var configurationFileStructure configurationFile.ConfigurationFile
var configurationFilePath string
var userHomeDir string

/*initialize get the configuration file existing in the system (or create it), and return
 *a pointer to his content.
 */
func initialize(configurationFileStructure *configurationFile.ConfigurationFile) {
	// Initialize all different traces structures
	traces.InitTraces(os.Stdout, os.Stderr, os.Stdout, os.Stdout)
	// Get the user home directory
	userHomeDir = utils.GetUserHomeDir()
	if len(userHomeDir) == 0 {
		log.Fatalf("cant get the user home dir\n")
	}
	// Set the configuration path file
	configurationFilePath = path.Join(userHomeDir, consts.ConfigurationFileName)
	filePointer, err := os.OpenFile(configurationFilePath, os.O_RDWR|os.O_CREATE, 0755)
	if err != nil {
		log.Fatalf("cant open the file %s, due to error '%s'\n", configurationFilePath, err)
	}
	defer filePointer.Close()
	var bytesArray []byte
	// Get the content of the goyave configuration file
	configurationFile.GetConfigurationFileContent(filePointer, &bytesArray)
	if _, err = toml.Decode(string(bytesArray[:]), configurationFileStructure); err != nil {
		log.Fatalln(err)
	}
	if err := configurationFileStructure.Process(); err != nil {
		log.Fatalln(err)
	}
}

/*kill saves the current state of the configuration structure in the configuration file
 */
func kill() {
	var outputBuffer bytes.Buffer
	// currentGroupIndex := utils.SliceIndex(len(configurationFileStructure.Groups), func(i int) bool {
	// 	return configurationFileStructure.Groups[i].Name == configurationFileStructure.Local.Group
	// })
	// var newVisibleRepositories []string
	// for _, visibleRepository := range configurationFileStructure.VisibleRepositories {
	// 	newVisibleRepositories = append(newVisibleRepositories, visibleRepository.Name)
	// }
	// configurationFileStructure.Groups[currentGroupIndex].VisibleRepositories = newVisibleRepositories
	if err := configurationFileStructure.Encode(&outputBuffer); err != nil {
		log.Fatalln("can't save the current configurationFile structure")
	}
	if err := ioutil.WriteFile(configurationFilePath, outputBuffer.Bytes(), 0777); err != nil {
		log.Fatalln("can't access to your file to save the configurationFile structure")
	}
}

func main() {

	/*rootCmd defines the global app, and some actions to run before and after the command running
	 */
	var rootCmd = &cobra.Command{
		Use:   "goyave",
		Short: "Goyave is a tool to take a look at your local git repositories",
		// Initialize the structure
		PersistentPreRun: func(cmd *cobra.Command, args []string) {
			initialize(&configurationFileStructure)
		},
		// Save the current configuration file structure, in the configuration file
		PersistentPostRun: func(cmd *cobra.Command, args []string) {
			kill()
		},
	}

	var initCmd = &cobra.Command{
		Use:   "init",
		Short: "Init",
		Run: func(cmd *cobra.Command, args []string) {
		},
	}

	/*addCmd is a subcommand to add the current working directory as a VISIBLE one
	 */
	// var addCmd = &cobra.Command{
	// 	Use:   "add",
	// 	Short: "Add the current path as a VISIBLE repository",
	// 	Run: func(cmd *cobra.Command, args []string) {
	// 		// Get the path where the command has been executed
	// 		currentDir, err := os.Getwd()
	// 		if err != nil {
	// 			log.Fatalln("There was a problem retrieving the current directory")
	// 		}
	// 		if !utils.IsGitRepository(currentDir) {
	// 			log.Fatalf("%s is not a git repository!\n", currentDir)
	// 		}
	// 		if err := configurationFileStructure.Extract(); err != nil {
	// 			traces.ErrorTracer.Fatalln(err)
	// 		}
	// 		// If the path is/contains a .git directory, add this one as a VISIBLE repository
	// 		if err := configurationFileStructure.AddRepository(currentDir, consts.VisibleFlag); err != nil {
	// 			traces.WarningTracer.Printf("[%s] %s\n", currentDir, err)
	// 		}
	// 	},
	// }

	/*crawlCmd is a subcommand to crawl your hard drive in order to get and save new git repositories
	 */
	var crawlCmd = &cobra.Command{
		Use:   "crawl",
		Short: "Crawl the hard drive in order to find git repositories",
		Run: func(cmd *cobra.Command, args []string) {
			var wg sync.WaitGroup
			// Get all git paths, and display them
			gitPaths, err := walk.RetrieveGitRepositories(userHomeDir)
			if err != nil {
				log.Fatalf("there was an error retrieving your git repositories: '%s'\n", err)
			}
			// For each git repository, check if it exists, and if not add it to the default target visibility
			for _, gitPath := range gitPaths {
				wg.Add(1)
				go func(gitPath string) {
					defer wg.Done()
					configurationFileStructure.AddRepository(gitPath, configurationFileStructure.Local.DefaultTarget)
				}(gitPath)
			}
			wg.Wait()
		},
	}

	/*loadCmd permits to load visible repositories from the goyave configuration file
	 */
	// var loadCmd = &cobra.Command{
	// 	Use:   "load",
	// 	Short: "Load the configuration file to restore your previous work space",
	// 	Run: func(cmd *cobra.Command, args []string) {
	// 		currentLocalhost := utils.GetLocalhost()
	// 		fmt.Printf("Current localhost is %s\n", currentLocalhost)
	// 		configGroups := configurationFileStructure.Groups
	// 		var visibleRepositories []string
	// 		for {
	// 			index := utils.SliceIndex(len(configGroups), func(i int) bool { return configGroups[i].Name == currentLocalhost })
	// 			if index == -1 {
	// 				traces.WarningTracer.Printf("Your current local host (%s) has not been found!", currentLocalhost)
	// 				fmt.Println("Please to choose one of those, to load the configuration file:")
	// 				for _, group := range configGroups {
	// 					fmt.Printf("\t%s\n", group.Name)
	// 				}
	// 				scanner := bufio.NewScanner(os.Stdin)
	// 				currentLocalhost = scanner.Text()
	// 				continue
	// 			} else {
	// 				visibleRepositories = configurationFileStructure.Groups[index].VisibleRepositories
	// 			}
	// 			break
	// 		}
	// 		traces.InfoTracer.Printf("Importing configuration from group %s\n", currentLocalhost)
	// 		for _, visibleRepository := range visibleRepositories {
	// 			traces.InfoTracer.Printf("* Importing %s...\n", visibleRepository)
	// 			index := utils.SliceIndex(len(configurationFileStructure.Repositories), func(i int) bool { return configurationFileStructure.Repositories[i].Name == visibleRepository })
	// 			// Check the local path, and the remote URL
	// 			if index == -1 {
	// 				traces.WarningTracer.Printf("\tThe repository \"%s\" does not exists in your configuration file.\n", visibleRepository)
	// 				continue
	// 			}
	// 			// Check if the repository exists locally
	// 			pathRepository, URLRepository := configurationFileStructure.Repositories[index].Path, configurationFileStructure.Repositories[index].URL
	// 			if _, err := os.Stat(pathRepository); err == nil {
	// 				traces.InfoTracer.Printf("\tThe repository \"%s\" already exists as a local git repository.\n", visibleRepository)
	// 				continue
	// 			}
	// 			// If it does not exists, clone it
	// 			if err := gitManip.Clone(pathRepository, URLRepository); err != nil {
	// 				traces.ErrorTracer.Printf("\tThe repository \"%s\" can't be cloned: %s\n", visibleRepository, err)
	// 			} else {
	// 				traces.InfoTracer.Printf("\tThe repository \"%s\" has been successfully cloned!\n", visibleRepository)
	// 			}
	// 		}
	// 	},
	// }

	/*pathCmd is a subcommand to get the path of a given git repository.
	 *This subcommand is useful to change directory, like `cd $(goyave path mygitrepo)`
	 */
	// var pathCmd = &cobra.Command{
	// 	Use:   "path",
	// 	Short: "Get the path of a given repository, if this one exists",
	// 	Run: func(cmd *cobra.Command, args []string) {
	// 		if len(args) == 0 {
	// 			log.Fatalln("Needs a repository name!")
	// 		}
	// 		repo := args[0]
	// 		if err := configurationFileStructure.Extract(true); err != nil {
	// 			traces.ErrorTracer.Fatalln(err)
	// 		}
	// 		repoPath := configurationFileStructure.GetPathFromRepository(repo)
	// 		if repoPath != "" {
	// 			fmt.Println(repoPath)
	// 		} else {
	// 			log.Fatalf("the repository %s does not exists\n", repo)
	// 		}
	// 	},
	// }

	/*stateCmd is a subcommand to list the state of each local git repository.
	 */
	// var stateCmd = &cobra.Command{
	// 	Use:     "state",
	// 	Example: "goyave state\ngoyave state myRepositoryName\ngoyave state myRepositoryName1 myRepositoryName2",
	// 	Short:   "Get the state of each local visible git repository",
	// 	Long:    "Check only visible git repositories.\nIf some repository names have been setted, goyave will only check those repositories, otherwise it checks all visible repositories of your system.",
	// 	Run: func(cmd *cobra.Command, args []string) {
	// 		if err := configurationFileStructure.Extract(true); err != nil {
	// 			traces.ErrorTracer.Fatalln(err)
	// 		}
	// 		var gitStructs []configurationFile.GitRepository
	// 		if len(args) == 0 {
	// 			gitStructs = configurationFileStructure.VisibleRepositories
	// 		} else {
	// 			// Sort visible repositories by name
	// 			sort.Sort(configurationFile.ByName(configurationFileStructure.VisibleRepositories))
	// 			repositoriesListLength := len(configurationFileStructure.VisibleRepositories)
	// 			// Looking for given repository names - if the looking one does not exists, let the function prints a warning message.
	// 			for _, repositoryName := range args {
	// 				repositoryIndex := sort.Search(repositoriesListLength, func(i int) bool { return configurationFileStructure.VisibleRepositories[i].Name >= repositoryName })
	// 				if repositoryIndex != repositoriesListLength {
	// 					gitStructs = append(gitStructs, configurationFileStructure.VisibleRepositories[repositoryIndex])
	// 				} else {
	// 					traces.WarningTracer.Printf("%s cannot be found in your visible repositories!\n", repositoryName)
	// 				}
	// 			}
	// 		}
	// 		var wg sync.WaitGroup
	// 		for _, gitStruct := range gitStructs {
	// 			wg.Add(1)
	// 			go func(gitStruct configurationFile.GitRepository) {
	// 				defer wg.Done()
	// 				gitStruct.Init(gitStruct.Path)
	// 				gitStruct.GitObject.Status()
	// 			}(gitStruct)
	// 		}
	// 		wg.Wait()
	// 	},
	// }

	/*switchCmd is a subcommand to switch the visibility of the current git repository.
	 */
	// var switchCmd = &cobra.Command{
	// 	Use:   "switch",
	// 	Short: "Switch the visibility of the current git repository (given by the current path)",
	// 	Run: func(cmd *cobra.Command, args []string) {
	// 		// Get the path where the command has been executed
	// 		currentDir, err := os.Getwd()
	// 		if err != nil {
	// 			log.Fatalln("there was a problem retrieving the current directory")
	// 		}
	// 		if err := configurationFileStructure.Extract(true); err != nil {
	// 			traces.ErrorTracer.Fatalln(err)
	// 		}
	// 		// Recognizing the repository in the configuration file
	// 		repositoryName := filepath.Base(currentDir)
	// 		localRepositories := configurationFileStructure.Repositories
	// 		repositoryPathIndex := utils.SliceIndex(len(localRepositories), func(i int) bool { return localRepositories[i].Name == repositoryName })
	// 		if repositoryPathIndex == -1 {
	// 			log.Fatalf("the repository '%s' does not exists in the configuration file", filepath.Base(currentDir))
	// 			os.Exit(2)
	// 		}
	// 		repositoryGroupIndex := utils.SliceIndex(len(localRepositories[repositoryPathIndex].Paths), func(i int) bool { return localRepositories[repositoryPathIndex].Paths[i].Path == currentDir })
	// 		if repositoryGroupIndex == -1 {
	// 			log.Fatalf("the file path '%s' does not exists in the configuration file", currentDir)
	// 			os.Exit(2)
	// 		}
	// 		// The repository is now recognized
	// 		currentGroupName := utils.GetLocalhost()
	// 		groupIndex := utils.SliceIndex(len(configurationFileStructure.Groups), func(i int) bool { return configurationFileStructure.Groups[i].Name == currentGroupName })
	// 		if groupIndex == -1 {
	// 			log.Fatalln("your localhost is not recognized, please to crawl first")
	// 			os.Exit(2)
	// 		}
	// 		visibleRepositories := configurationFileStructure.VisibleRepositories
	// 		// visibleRepositories := configurationFileStructure.Groups[groupIndex].VisibleRepositories
	// 		repositoryIndex := utils.SliceIndex(len(visibleRepositories), func(i int) bool { return visibleRepositories[i].Name == repositoryName })
	// 		if repositoryIndex == -1 {
	// 			configurationFileStructure.AddRepository(currentDir, consts.VisibleFlag)
	// 			fmt.Printf("The repository %s has been added!\n", repositoryName)
	// 		} else {
	// 			configurationFileStructure.VisibleRepositories = append(visibleRepositories[:repositoryIndex], visibleRepositories[repositoryIndex+1:]...)
	// 			fmt.Printf("The repository %s has been removed!\n", repositoryName)
	// 		}
	// 		fmt.Println(configurationFileStructure.VisibleRepositories)
	// 	},
	// }

	// rootCmd.AddCommand(crawlCmd, pathCmd, stateCmd)

	rootCmd.AddCommand(initCmd, crawlCmd)

	if err := rootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}
<commit_msg>Add new command(s)<commit_after>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"
	"sync"

	"github.com/BurntSushi/toml"
	"github.com/k0pernicus/goyave/configurationFile"
	"github.com/k0pernicus/goyave/consts"
	"github.com/k0pernicus/goyave/gitManip"
	"github.com/k0pernicus/goyave/traces"
	"github.com/k0pernicus/goyave/utils"
	"github.com/k0pernicus/goyave/walk"
	"github.com/spf13/cobra"
)

var configurationFileStructure configurationFile.ConfigurationFile
var configurationFilePath string
var userHomeDir string

/*initialize get the configuration file existing in the system (or create it), and return
 *a pointer to his content.
 */
func initialize(configurationFileStructure *configurationFile.ConfigurationFile) {
	// Initialize all different traces structures
	traces.InitTraces(os.Stdout, os.Stderr, os.Stdout, os.Stdout)
	// Get the user home directory
	userHomeDir = utils.GetUserHomeDir()
	if len(userHomeDir) == 0 {
		log.Fatalf("cant get the user home dir\n")
	}
	// Set the configuration path file
	configurationFilePath = path.Join(userHomeDir, consts.ConfigurationFileName)
	filePointer, err := os.OpenFile(configurationFilePath, os.O_RDWR|os.O_CREATE, 0755)
	if err != nil {
		log.Fatalf("cant open the file %s, due to error '%s'\n", configurationFilePath, err)
	}
	defer filePointer.Close()
	var bytesArray []byte
	// Get the content of the goyave configuration file
	configurationFile.GetConfigurationFileContent(filePointer, &bytesArray)
	if _, err = toml.Decode(string(bytesArray[:]), configurationFileStructure); err != nil {
		log.Fatalln(err)
	}
	if err := configurationFileStructure.Process(); err != nil {
		log.Fatalln(err)
	}
}

/*kill saves the current state of the configuration structure in the configuration file
 */
func kill() {
	var outputBuffer bytes.Buffer
	if err := configurationFileStructure.Encode(&outputBuffer); err != nil {
		log.Fatalln("can't save the current configurationFile structure")
	}
	if err := ioutil.WriteFile(configurationFilePath, outputBuffer.Bytes(), 0777); err != nil {
		log.Fatalln("can't access to your file to save the configurationFile structure")
	}
}

func main() {

	/*rootCmd defines the global app, and some actions to run before and after the command running
	 */
	var rootCmd = &cobra.Command{
		Use:   "goyave",
		Short: "Goyave is a tool to take a look at your local git repositories",
		// Initialize the structure
		PersistentPreRun: func(cmd *cobra.Command, args []string) {
			initialize(&configurationFileStructure)
		},
		// Save the current configuration file structure, in the configuration file
		PersistentPostRun: func(cmd *cobra.Command, args []string) {
			kill()
		},
	}

	var initCmd = &cobra.Command{
		Use:   "init",
		Short: "Init",
		Run: func(cmd *cobra.Command, args []string) {
		},
	}

	/*addCmd is a subcommand to add the current working directory as a VISIBLE one
	 */
	// var addCmd = &cobra.Command{
	// 	Use:   "add",
	// 	Short: "Add the current path as a VISIBLE repository",
	// 	Run: func(cmd *cobra.Command, args []string) {
	// 		// Get the path where the command has been executed
	// 		currentDir, err := os.Getwd()
	// 		if err != nil {
	// 			log.Fatalln("There was a problem retrieving the current directory")
	// 		}
	// 		if !utils.IsGitRepository(currentDir) {
	// 			log.Fatalf("%s is not a git repository!\n", currentDir)
	// 		}
	// 		if err := configurationFileStructure.Extract(); err != nil {
	// 			traces.ErrorTracer.Fatalln(err)
	// 		}
	// 		// If the path is/contains a .git directory, add this one as a VISIBLE repository
	// 		if err := configurationFileStructure.AddRepository(currentDir, consts.VisibleFlag); err != nil {
	// 			traces.WarningTracer.Printf("[%s] %s\n", currentDir, err)
	// 		}
	// 	},
	// }

	/*crawlCmd is a subcommand to crawl your hard drive in order to get and save new git repositories
	 */
	var crawlCmd = &cobra.Command{
		Use:   "crawl",
		Short: "Crawl the hard drive in order to find git repositories",
		Run: func(cmd *cobra.Command, args []string) {
			var wg sync.WaitGroup
			// Get all git paths, and display them
			gitPaths, err := walk.RetrieveGitRepositories(userHomeDir)
			if err != nil {
				log.Fatalf("there was an error retrieving your git repositories: '%s'\n", err)
			}
			// For each git repository, check if it exists, and if not add it to the default target visibility
			for _, gitPath := range gitPaths {
				wg.Add(1)
				go func(gitPath string) {
					defer wg.Done()
					configurationFileStructure.AddRepository(gitPath, configurationFileStructure.Local.DefaultTarget)
				}(gitPath)
			}
			wg.Wait()
		},
	}

	/*loadCmd permits to load visible repositories from the goyave configuration file
	 */
	// var loadCmd = &cobra.Command{
	// 	Use:   "load",
	// 	Short: "Load the configuration file to restore your previous work space",
	// 	Run: func(cmd *cobra.Command, args []string) {
	// 		currentLocalhost := utils.GetLocalhost()
	// 		fmt.Printf("Current localhost is %s\n", currentLocalhost)
	// 		configGroups := configurationFileStructure.Groups
	// 		var visibleRepositories []string
	// 		for {
	// 			index := utils.SliceIndex(len(configGroups), func(i int) bool { return configGroups[i].Name == currentLocalhost })
	// 			if index == -1 {
	// 				traces.WarningTracer.Printf("Your current local host (%s) has not been found!", currentLocalhost)
	// 				fmt.Println("Please to choose one of those, to load the configuration file:")
	// 				for _, group := range configGroups {
	// 					fmt.Printf("\t%s\n", group.Name)
	// 				}
	// 				scanner := bufio.NewScanner(os.Stdin)
	// 				currentLocalhost = scanner.Text()
	// 				continue
	// 			} else {
	// 				visibleRepositories = configurationFileStructure.Groups[index].VisibleRepositories
	// 			}
	// 			break
	// 		}
	// 		traces.InfoTracer.Printf("Importing configuration from group %s\n", currentLocalhost)
	// 		for _, visibleRepository := range visibleRepositories {
	// 			traces.InfoTracer.Printf("* Importing %s...\n", visibleRepository)
	// 			index := utils.SliceIndex(len(configurationFileStructure.Repositories), func(i int) bool { return configurationFileStructure.Repositories[i].Name == visibleRepository })
	// 			// Check the local path, and the remote URL
	// 			if index == -1 {
	// 				traces.WarningTracer.Printf("\tThe repository \"%s\" does not exists in your configuration file.\n", visibleRepository)
	// 				continue
	// 			}
	// 			// Check if the repository exists locally
	// 			pathRepository, URLRepository := configurationFileStructure.Repositories[index].Path, configurationFileStructure.Repositories[index].URL
	// 			if _, err := os.Stat(pathRepository); err == nil {
	// 				traces.InfoTracer.Printf("\tThe repository \"%s\" already exists as a local git repository.\n", visibleRepository)
	// 				continue
	// 			}
	// 			// If it does not exists, clone it
	// 			if err := gitManip.Clone(pathRepository, URLRepository); err != nil {
	// 				traces.ErrorTracer.Printf("\tThe repository \"%s\" can't be cloned: %s\n", visibleRepository, err)
	// 			} else {
	// 				traces.InfoTracer.Printf("\tThe repository \"%s\" has been successfully cloned!\n", visibleRepository)
	// 			}
	// 		}
	// 	},
	// }

	/*pathCmd is a subcommand to get the path of a given git repository.
	 *This subcommand is useful to change directory, like `cd $(goyave path mygitrepo)`
	 */
	var pathCmd = &cobra.Command{
		Use:   "path",
		Short: "Get the path of a given repository, if this one exists",
		Run: func(cmd *cobra.Command, args []string) {
			if len(args) == 0 {
				log.Fatalln("Needs a repository name!")
			}
			repo := args[0]
			repoPath, found := configurationFileStructure.GetPath(repo)
			if !found {
				log.Fatalf("repository %s not found\n", repo)
			} else {
				fmt.Println(repoPath)
			}
		},
	}

	/*stateCmd is a subcommand to list the state of each local git repository.
	 */
	var stateCmd = &cobra.Command{
		Use:     "state",
		Example: "goyave state\ngoyave state myRepositoryName\ngoyave state myRepositoryName1 myRepositoryName2",
		Short:   "Get the state of each local visible git repository",
		Long:    "Check only visible git repositories.\nIf some repository names have been setted, goyave will only check those repositories, otherwise it checks all visible repositories of your system.",
		Run: func(cmd *cobra.Command, args []string) {
			var paths []string
			// Append repositories to check
			if len(args) == 0 {
				for _, p := range configurationFileStructure.VisibleRepositories {
					paths = append(paths, p)
				}
			} else {
				for _, repository := range args {
					repoPath, ok := configurationFileStructure.VisibleRepositories[repository]
					if ok {
						paths = append(paths, repoPath)
					} else {
						traces.WarningTracer.Printf("%s cannot be found in your visible repositories\n", repository)
					}
				}
			}
			var wg sync.WaitGroup
			for _, repository := range paths {
				wg.Add(1)
				go func(repoPath string) {
					defer wg.Done()
					cGitObj := gitManip.New(repoPath)
					cGitObj.Status()
				}(repository)
			}
			wg.Wait()
		},
	}

	/*switchCmd is a subcommand to switch the visibility of the current git repository.
	 */
	// var switchCmd = &cobra.Command{
	// 	Use:   "switch",
	// 	Short: "Switch the visibility of the current git repository (given by the current path)",
	// 	Run: func(cmd *cobra.Command, args []string) {
	// 		// Get the path where the command has been executed
	// 		currentDir, err := os.Getwd()
	// 		if err != nil {
	// 			log.Fatalln("there was a problem retrieving the current directory")
	// 		}
	// 		if err := configurationFileStructure.Extract(true); err != nil {
	// 			traces.ErrorTracer.Fatalln(err)
	// 		}
	// 		// Recognizing the repository in the configuration file
	// 		repositoryName := filepath.Base(currentDir)
	// 		localRepositories := configurationFileStructure.Repositories
	// 		repositoryPathIndex := utils.SliceIndex(len(localRepositories), func(i int) bool { return localRepositories[i].Name == repositoryName })
	// 		if repositoryPathIndex == -1 {
	// 			log.Fatalf("the repository '%s' does not exists in the configuration file", filepath.Base(currentDir))
	// 			os.Exit(2)
	// 		}
	// 		repositoryGroupIndex := utils.SliceIndex(len(localRepositories[repositoryPathIndex].Paths), func(i int) bool { return localRepositories[repositoryPathIndex].Paths[i].Path == currentDir })
	// 		if repositoryGroupIndex == -1 {
	// 			log.Fatalf("the file path '%s' does not exists in the configuration file", currentDir)
	// 			os.Exit(2)
	// 		}
	// 		// The repository is now recognized
	// 		currentGroupName := utils.GetLocalhost()
	// 		groupIndex := utils.SliceIndex(len(configurationFileStructure.Groups), func(i int) bool { return configurationFileStructure.Groups[i].Name == currentGroupName })
	// 		if groupIndex == -1 {
	// 			log.Fatalln("your localhost is not recognized, please to crawl first")
	// 			os.Exit(2)
	// 		}
	// 		visibleRepositories := configurationFileStructure.VisibleRepositories
	// 		// visibleRepositories := configurationFileStructure.Groups[groupIndex].VisibleRepositories
	// 		repositoryIndex := utils.SliceIndex(len(visibleRepositories), func(i int) bool { return visibleRepositories[i].Name == repositoryName })
	// 		if repositoryIndex == -1 {
	// 			configurationFileStructure.AddRepository(currentDir, consts.VisibleFlag)
	// 			fmt.Printf("The repository %s has been added!\n", repositoryName)
	// 		} else {
	// 			configurationFileStructure.VisibleRepositories = append(visibleRepositories[:repositoryIndex], visibleRepositories[repositoryIndex+1:]...)
	// 			fmt.Printf("The repository %s has been removed!\n", repositoryName)
	// 		}
	// 		fmt.Println(configurationFileStructure.VisibleRepositories)
	// 	},
	// }

	// rootCmd.AddCommand(crawlCmd, pathCmd, stateCmd)

	rootCmd.AddCommand(crawlCmd, initCmd, pathCmd, stateCmd)

	if err := rootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"math/rand"

	tl "github.com/JoelOtter/termloop"
	"github.com/andoco/gotermlife/sim"
)

type SimLevel struct {
	*tl.BaseLevel
	sim     *sim.S
	offsetX int
	offsetY int
}

var liveCell *tl.Cell

func (sl *SimLevel) Tick(event tl.Event) {
	if event.Type == tl.EventKey { // Is it a keyboard event?
		switch event.Key { // If so, switch on the pressed key.
		case tl.KeySpace:
			sl.sim.Tick()
		case tl.KeyArrowUp:
			sl.offsetY += 1
		case tl.KeyArrowDown:
			sl.offsetY -= 1
		case tl.KeyArrowLeft:
			sl.offsetX += 1
		case tl.KeyArrowRight:
			sl.offsetX -= 1
		}
	}

	sl.sim.Tick()
}

func (sl *SimLevel) Draw(s *tl.Screen) {
	for _, c := range sl.sim.Cells {
		if c.Live {
			s.RenderCell(sl.offsetX+c.Pos.X, sl.offsetY+c.Pos.Y, liveCell)
		}
	}
}

func main() {
	liveCell = &tl.Cell{Ch: '◼'}

	s := sim.New()
	//s.Seed([]sim.P{{5, 5}, {6, 5}, {7, 5}})

	seed := []sim.P{}
	for i := 0; i < 1000; i++ {
		seed = append(seed, sim.P{rand.Intn(80), rand.Intn(80)})
	}
	s.Seed(seed)

	game := tl.NewGame()

	level := tl.NewBaseLevel(tl.Cell{})

	simLevel := &SimLevel{level, s, 0, 0}

	game.Screen().SetLevel(simLevel)
	game.Screen().SetFps(10)
	game.Start()
}
<commit_msg>Smaller start area<commit_after>package main

import (
	"math/rand"

	tl "github.com/JoelOtter/termloop"
	"github.com/andoco/gotermlife/sim"
)

type SimLevel struct {
	*tl.BaseLevel
	sim     *sim.S
	offsetX int
	offsetY int
}

var liveCell *tl.Cell

func (sl *SimLevel) Tick(event tl.Event) {
	if event.Type == tl.EventKey { // Is it a keyboard event?
		switch event.Key { // If so, switch on the pressed key.
		case tl.KeySpace:
			sl.sim.Tick()
		case tl.KeyArrowUp:
			sl.offsetY += 1
		case tl.KeyArrowDown:
			sl.offsetY -= 1
		case tl.KeyArrowLeft:
			sl.offsetX += 1
		case tl.KeyArrowRight:
			sl.offsetX -= 1
		}
	}

	sl.sim.Tick()
}

func (sl *SimLevel) Draw(s *tl.Screen) {
	for _, c := range sl.sim.Cells {
		if c.Live {
			s.RenderCell(sl.offsetX+c.Pos.X, sl.offsetY+c.Pos.Y, liveCell)
		}
	}
}

func main() {
	liveCell = &tl.Cell{Ch: '◼'}

	s := sim.New()
	//s.Seed([]sim.P{{5, 5}, {6, 5}, {7, 5}})

	seed := []sim.P{}
	for i := 0; i < 1000; i++ {
		seed = append(seed, sim.P{rand.Intn(80), rand.Intn(40)})
	}
	s.Seed(seed)

	game := tl.NewGame()

	level := tl.NewBaseLevel(tl.Cell{})

	simLevel := &SimLevel{level, s, 0, 0}

	game.Screen().SetLevel(simLevel)
	game.Screen().SetFps(10)
	game.Start()
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"io"
	"os"
	"path"
	"strings"
)

func print(w io.Writer, pkg *ast.Package, kind ast.ObjKind, format string) {
	for _, f := range pkg.Files {
		for name, object := range f.Scope.Objects {
			if object.Kind == kind && (unexported || ast.IsExported(name)) {
				fmt.Fprintf(w, format, name, name)
			}
		}
	}
}

func filter(info os.FileInfo) bool {
	name := info.Name()
	return !info.IsDir() && name != gofile && path.Ext(name) == ".go" && !strings.HasSuffix(name, "_test.go")
}

func parseDir(dir string) {
	dirFile, err := os.Open(dir)
	if err != nil {
		panic(err)
	}
	defer dirFile.Close()
	info, err := dirFile.Stat()
	if err != nil {
		panic(err)
	}
	if !info.IsDir() {
		panic("Path is not a directory: " + dir)
	}

	pkgs, err := parser.ParseDir(token.NewFileSet(), dir, filter, 0)
	if err != nil {
		panic(err)
	}
	for _, pkg := range pkgs {
		file, err := os.Create(path.Join(dir, gofile))
		if err != nil {
			panic(err)
		}
		defer file.Close()
		fmt.Fprintln(file, "// File generated by github.com/ungerik/pkgreflect")
		fmt.Fprintln(file, "package", pkg.Name)
		fmt.Fprintln(file, "")
		fmt.Fprintln(file, `import "reflect"`)
		fmt.Fprintln(file, "")

		// Types
		if !notypes {
			fmt.Fprintln(file, "var Types = map[string]reflect.Type{")
			print(file, pkg, ast.Typ, "\t\"%s\": reflect.TypeOf((*%s)(nil)).Elem(),\n")
			fmt.Fprintln(file, "}")
			fmt.Fprintln(file, "")
		}

		// Functions
		if !nofuncs {
			fmt.Fprintln(file, "var Functions = map[string]reflect.Value{")
			print(file, pkg, ast.Fun, "\t\"%s\": reflect.ValueOf(%s),\n")
			fmt.Fprintln(file, "}")
			fmt.Fprintln(file, "")
		}

		if !novars {
			// Addresses of variables
			fmt.Fprintln(file, "var Variables = map[string]reflect.Value{")
			print(file, pkg, ast.Var, "\t\"%s\": reflect.ValueOf(&%s),\n")
			fmt.Fprintln(file, "}")
			fmt.Fprintln(file, "")
		}
	}

	if !norecurs {
		dirs, err := dirFile.Readdir(-1)
		if err != nil {
			panic(err)
		}
		for _, info := range dirs {
			if info.IsDir() {
				parseDir(path.Join(dir, info.Name()))
			}
		}
	}
}

var (
	notypes    bool
	nofuncs    bool
	novars     bool
	unexported bool
	norecurs   bool
	gofile     string
)

func main() {
	flag.BoolVar(&notypes, "notypes", false, "Don't list package types")
	flag.BoolVar(&nofuncs, "nofuncs", false, "Don't list package functions")
	flag.BoolVar(&novars, "novars", false, "Don't list package variables")
	flag.BoolVar(&unexported, "unexported", false, "Also list unexported names")
	flag.BoolVar(&norecurs, "norecurs", false, "Don't parse sub-directories resursively")
	flag.StringVar(&gofile, "gofile", "pkgreflect.go", "Name of the generated .go file")
	flag.Parse()

	if len(flag.Args()) > 0 {
		for _, dir := range flag.Args() {
			parseDir(dir)
		}
	} else {
		parseDir(".")
	}
}
<commit_msg>added docu from readme to main<commit_after>/*
Go reflection does not support enumerating types, variables and functions of packages.

pkgreflect generates a file named pkgreflect.go in every parsed package directory.
This file contains the follwing maps of exported names to reflection types/values:

	var Types = map[string]reflect.Type{ ... }
	var Functions = map[string]reflect.Value{ ... }
	var Variables = map[string]reflect.Value{ ... }

Command line usage:

	pkgreflect --help
	pkgreflect [-notypes][-nofuncs][-novars][-unexported][-norecurs][-gofile=filename.go] [DIR_NAME]

If -norecurs is not set, then pkgreflect traverses recursively into sub-directories.
If no DIR_NAME is given, then the current directory is used as root.
*/
package main

import (
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"io"
	"os"
	"path"
	"strings"
)

func print(w io.Writer, pkg *ast.Package, kind ast.ObjKind, format string) {
	for _, f := range pkg.Files {
		for name, object := range f.Scope.Objects {
			if object.Kind == kind && (unexported || ast.IsExported(name)) {
				fmt.Fprintf(w, format, name, name)
			}
		}
	}
}

func filter(info os.FileInfo) bool {
	name := info.Name()
	return !info.IsDir() && name != gofile && path.Ext(name) == ".go" && !strings.HasSuffix(name, "_test.go")
}

func parseDir(dir string) {
	dirFile, err := os.Open(dir)
	if err != nil {
		panic(err)
	}
	defer dirFile.Close()
	info, err := dirFile.Stat()
	if err != nil {
		panic(err)
	}
	if !info.IsDir() {
		panic("Path is not a directory: " + dir)
	}

	pkgs, err := parser.ParseDir(token.NewFileSet(), dir, filter, 0)
	if err != nil {
		panic(err)
	}
	for _, pkg := range pkgs {
		file, err := os.Create(path.Join(dir, gofile))
		if err != nil {
			panic(err)
		}
		defer file.Close()
		fmt.Fprintln(file, "// File generated by github.com/ungerik/pkgreflect")
		fmt.Fprintln(file, "package", pkg.Name)
		fmt.Fprintln(file, "")
		fmt.Fprintln(file, `import "reflect"`)
		fmt.Fprintln(file, "")

		// Types
		if !notypes {
			fmt.Fprintln(file, "var Types = map[string]reflect.Type{")
			print(file, pkg, ast.Typ, "\t\"%s\": reflect.TypeOf((*%s)(nil)).Elem(),\n")
			fmt.Fprintln(file, "}")
			fmt.Fprintln(file, "")
		}

		// Functions
		if !nofuncs {
			fmt.Fprintln(file, "var Functions = map[string]reflect.Value{")
			print(file, pkg, ast.Fun, "\t\"%s\": reflect.ValueOf(%s),\n")
			fmt.Fprintln(file, "}")
			fmt.Fprintln(file, "")
		}

		if !novars {
			// Addresses of variables
			fmt.Fprintln(file, "var Variables = map[string]reflect.Value{")
			print(file, pkg, ast.Var, "\t\"%s\": reflect.ValueOf(&%s),\n")
			fmt.Fprintln(file, "}")
			fmt.Fprintln(file, "")
		}
	}

	if !norecurs {
		dirs, err := dirFile.Readdir(-1)
		if err != nil {
			panic(err)
		}
		for _, info := range dirs {
			if info.IsDir() {
				parseDir(path.Join(dir, info.Name()))
			}
		}
	}
}

var (
	notypes    bool
	nofuncs    bool
	novars     bool
	unexported bool
	norecurs   bool
	gofile     string
)

func main() {
	flag.BoolVar(&notypes, "notypes", false, "Don't list package types")
	flag.BoolVar(&nofuncs, "nofuncs", false, "Don't list package functions")
	flag.BoolVar(&novars, "novars", false, "Don't list package variables")
	flag.BoolVar(&unexported, "unexported", false, "Also list unexported names")
	flag.BoolVar(&norecurs, "norecurs", false, "Don't parse sub-directories resursively")
	flag.StringVar(&gofile, "gofile", "pkgreflect.go", "Name of the generated .go file")
	flag.Parse()

	if len(flag.Args()) > 0 {
		for _, dir := range flag.Args() {
			parseDir(dir)
		}
	} else {
		parseDir(".")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/x509"
	"encoding/pem"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"

	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	"github.com/flexiant/concerto/admin"
	"github.com/flexiant/concerto/audit"
	"github.com/flexiant/concerto/blueprint/scripts"
	"github.com/flexiant/concerto/blueprint/services"
	"github.com/flexiant/concerto/blueprint/templates"
	"github.com/flexiant/concerto/cloud/generic_images"
	"github.com/flexiant/concerto/cloud/providers"
	"github.com/flexiant/concerto/cloud/saas_providers"
	"github.com/flexiant/concerto/cloud/server_plan"
	"github.com/flexiant/concerto/cloud/servers"
	"github.com/flexiant/concerto/cloud/ssh_profiles"
	"github.com/flexiant/concerto/cloud/workspaces"
	"github.com/flexiant/concerto/cluster"
	"github.com/flexiant/concerto/converge"
	"github.com/flexiant/concerto/dispatcher"
	"github.com/flexiant/concerto/dns"
	"github.com/flexiant/concerto/firewall"
	"github.com/flexiant/concerto/licensee"
	"github.com/flexiant/concerto/network/firewall_profiles"
	"github.com/flexiant/concerto/network/load_balancers"
	"github.com/flexiant/concerto/node"
	"github.com/flexiant/concerto/settings/cloud_accounts"
	"github.com/flexiant/concerto/settings/reports"
	"github.com/flexiant/concerto/settings/saas_accounts"
	"github.com/flexiant/concerto/utils"
	"github.com/flexiant/concerto/wizard/apps"
	"github.com/flexiant/concerto/wizard/cloud_providers"
	"github.com/flexiant/concerto/wizard/locations"
	"github.com/flexiant/concerto/wizard/server_plans"
)

func initLogging(lvl log.Level) {
	log.SetOutput(os.Stderr)
	log.SetLevel(lvl)
}

var ServerCommands = []cli.Command{
	{
		Name:  "firewall",
		Usage: "Manages Firewall Policies within a Host",
		Subcommands: append(
			firewall.SubCommands(),
		),
	},
	{
		Name:  "scripts",
		Usage: "Manages Execution Scripts within a Host",
		Subcommands: append(
			dispatcher.SubCommands(),
		),
	},
	{
		Name:   "converge",
		Usage:  "Converges Host to original Blueprint",
		Action: converge.CmbConverge,
	},
}

var BlueprintCommands = []cli.Command{
	{
		Name:  "scripts",
		Usage: "Allow the user to manage the scripts they want to run on the servers",
		Subcommands: append(
			scripts.SubCommands(),
		),
	},
	{
		Name:  "services",
		Usage: "Provides information on services",
		Subcommands: append(
			services.SubCommands(),
		),
	},
	{
		Name:  "templates",
		Usage: "Provides information on templates",
		Subcommands: append(
			templates.SubCommands(),
		),
	},
}

var CloudCommands = []cli.Command{
	{
		Name:  "workspaces",
		Usage: "Provides information on workspaces",
		Subcommands: append(
			workspaces.SubCommands(),
		),
	},
	{
		Name:  "servers",
		Usage: "Provides information on servers",
		Subcommands: append(
			servers.SubCommands(),
		),
	},
	{
		Name:  "generic_images",
		Usage: "Provides information on generic images",
		Subcommands: append(
			generic_images.SubCommands(),
		),
	},
	{
		Name:  "ssh_profiles",
		Usage: "Provides information on SSH profiles",
		Subcommands: append(
			ssh_profiles.SubCommands(),
		),
	},
	{
		Name:  "cloud_providers",
		Usage: "Provides information on cloud providers",
		Subcommands: append(
			providers.SubCommands(),
		),
	},
	{
		Name:  "server_plans",
		Usage: "Provides information on server plans",
		Subcommands: append(
			server_plan.SubCommands(),
		),
	},
	{
		Name:  "saas_providers",
		Usage: "Provides information about SAAS providers",
		Subcommands: append(
			saas_providers.SubCommands(),
		),
	},
}

var NetCommands = []cli.Command{
	{
		Name:  "firewall_profiles",
		Usage: "Provides information about firewall profiles",
		Subcommands: append(
			firewall_profiles.SubCommands(),
		),
	},
	{
		Name:  "load_balancers",
		Usage: "Provides information about load balancers",
		Subcommands: append(
			load_balancers.SubCommands(),
		),
	},
}

var SettingsCommands = []cli.Command{
	{
		Name:  "cloud_accounts",
		Usage: "Provides information about cloud accounts",
		Subcommands: append(
			cloud_accounts.SubCommands(),
		),
	},
	{
		Name:  "reports",
		Usage: "Provides information about reports",
		Subcommands: append(
			reports.SubCommands(),
		),
	},
	{
		Name:  "saas_accounts",
		Usage: "Provides information about SaaS accounts",
		Subcommands: append(
			saas_accounts.SubCommands(),
		),
	},
}

var WizardCommands = []cli.Command{
	{
		Name:  "apps",
		Usage: "Provides information about apps",
		Subcommands: append(
			apps.SubCommands(),
		),
	},
	{
		Name:  "cloud_providers",
		Usage: "Provides information about cloud providers",
		Subcommands: append(
			cloud_providers.SubCommands(),
		),
	},
	{
		Name:  "locations",
		Usage: "Provides information about locations",
		Subcommands: append(
			locations.SubCommands(),
		),
	},
	{
		Name:  "server_plans",
		Usage: "Provides information about server plans",
		Subcommands: append(
			server_plans.SubCommands(),
		),
	},
}

var ClientCommands = []cli.Command{
	{
		Name:      "nodes",
		ShortName: "no",
		Usage:     "Manages Docker Nodes",
		Subcommands: append(
			node.SubCommands(),
		),
	},
	{
		Name:      "cluster",
		ShortName: "clu",
		Usage:     "Manages a Kubernetes Cluster",
		Subcommands: append(
			cluster.SubCommands(),
		),
	},
	{
		Name:      "reports",
		ShortName: "rep",
		Usage:     "Provides historical uptime of servers",
		Subcommands: append(
			admin.SubCommands(),
		),
	},
	{
		Name:      "events",
		ShortName: "ev",
		Usage:     "Events allow the user to track their actions and the state of their servers",
		Subcommands: append(
			audit.SubCommands(),
		),
	},

	{
		Name:      "blueprint",
		ShortName: "bl",
		Usage:     "Manages blueprint commands for scripts, services and templates",
		Subcommands: append(
			BlueprintCommands,
		),
	},
	{
		Name:      "cloud",
		ShortName: "clo",
		Usage:     "Manages cloud related commands for workspaces, servers, generic images, ssh profiles, cloud providers, server plans and Saas providers",
		Subcommands: append(
			CloudCommands,
		),
	},
	{
		Name:      "dns_domains",
		ShortName: "dns",
		Usage:     "Provides information about DNS records",
		Subcommands: append(
			dns.SubCommands(),
		),
	},
	{
		Name:      "licensee_reports",
		ShortName: "lic",
		Usage:     "Provides information about licensee reports",
		Subcommands: append(
			licensee.SubCommands(),
		),
	},
	{
		Name:      "network",
		ShortName: "net",
		Usage:     "Manages network related commands for firewall profiles and load balancers",
		Subcommands: append(
			NetCommands,
		),
	},
	{
		Name:      "settings",
		ShortName: "set",
		Usage:     "Provides settings for cloud and Saas accounts as well as reports",
		Subcommands: append(
			SettingsCommands,
		),
	},
	{
		Name:      "wizard",
		ShortName: "wiz",
		Usage:     "Manages wizard related commands for apps, locations, cloud providers, server plans",
		Subcommands: append(
			WizardCommands,
		),
	},
}

func cmdNotFound(c *cli.Context, command string) {
	log.Fatalf(
		"%s: '%s' is not a %s command. See '%s --help'.",
		c.App.Name,
		command,
		c.App.Name,
		c.App.Name,
	)
}

func checkError(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func isUserCertificate(filename string) bool {
	if utils.Exists(filename) {
		data, err := ioutil.ReadFile(filename)
		checkError(err)
		block, _ := pem.Decode(data)

		cert, err := x509.ParseCertificate(block.Bytes)
		checkError(err)

		if len(cert.Subject.OrganizationalUnit) > 0 {
			if cert.Subject.OrganizationalUnit[0] == "Users" {
				return true

			}
		}
	}
	return false
}

func main() {

	for _, f := range os.Args {
		if f == "-D" || f == "--debug" || f == "-debug" {
			os.Setenv("DEBUG", "1")
			initLogging(log.DebugLevel)
		}
	}

	app := cli.NewApp()
	app.Name = path.Base(os.Args[0])
	app.Author = "Concerto Contributors"
	app.Email = "https://github.com/flexiant/concerto"

	app.CommandNotFound = cmdNotFound
	app.Usage = "Manages comunication between Host and Concerto Platform"
	app.Version = utils.VERSION

	if isUserCertificate(filepath.Join(utils.GetConcertoDir(), "ssl", "cert.crt")) {
		app.Commands = ClientCommands
	} else {
		app.Commands = ServerCommands
	}

	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "debug, D",
			Usage: "Enable debug mode",
		},
		cli.StringFlag{
			EnvVar: "CONCERTO_CA_CERT",
			Name:   "ca-cert",
			Usage:  "CA to verify remotes against",
			Value:  filepath.Join(utils.GetConcertoDir(), "ssl", "ca_cert.pem"),
		},
		cli.StringFlag{
			EnvVar: "CONCERTO_CLIENT_CERT",
			Name:   "client-cert",
			Usage:  "Client cert to use for Concerto",
			Value:  filepath.Join(utils.GetConcertoDir(), "ssl", "cert.crt"),
		},
		cli.StringFlag{
			EnvVar: "CONCERTO_CLIENT_KEY",
			Name:   "client-key",
			Usage:  "Private key used in client Concerto auth",
			Value:  filepath.Join(utils.GetConcertoDir(), "ssl", "/private/cert.key"),
		},
		cli.StringFlag{
			EnvVar: "CONCERTO_CONFIG",
			Name:   "concerto-config",
			Usage:  "Concerto Config File",
			Value:  filepath.Join(utils.GetConcertoDir(), "client.xml"),
		},
		cli.StringFlag{
			EnvVar: "CONCERTO_ENDPOINT",
			Name:   "concerto-endpoint",
			Usage:  "Concerto Endpoint",
			Value:  os.Getenv("CONCERTO_ENDPOINT"),
		},
	}

	app.Run(os.Args)
}
<commit_msg>[CARM-404] Change preference in loading default client settings<commit_after>package main

import (
	"crypto/x509"
	"encoding/pem"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"

	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	"github.com/flexiant/concerto/admin"
	"github.com/flexiant/concerto/audit"
	"github.com/flexiant/concerto/blueprint/scripts"
	"github.com/flexiant/concerto/blueprint/services"
	"github.com/flexiant/concerto/blueprint/templates"
	"github.com/flexiant/concerto/cloud/generic_images"
	"github.com/flexiant/concerto/cloud/providers"
	"github.com/flexiant/concerto/cloud/saas_providers"
	"github.com/flexiant/concerto/cloud/server_plan"
	"github.com/flexiant/concerto/cloud/servers"
	"github.com/flexiant/concerto/cloud/ssh_profiles"
	"github.com/flexiant/concerto/cloud/workspaces"
	"github.com/flexiant/concerto/cluster"
	"github.com/flexiant/concerto/converge"
	"github.com/flexiant/concerto/dispatcher"
	"github.com/flexiant/concerto/dns"
	"github.com/flexiant/concerto/firewall"
	"github.com/flexiant/concerto/licensee"
	"github.com/flexiant/concerto/network/firewall_profiles"
	"github.com/flexiant/concerto/network/load_balancers"
	"github.com/flexiant/concerto/node"
	"github.com/flexiant/concerto/settings/cloud_accounts"
	"github.com/flexiant/concerto/settings/reports"
	"github.com/flexiant/concerto/settings/saas_accounts"
	"github.com/flexiant/concerto/utils"
	"github.com/flexiant/concerto/wizard/apps"
	"github.com/flexiant/concerto/wizard/cloud_providers"
	"github.com/flexiant/concerto/wizard/locations"
	"github.com/flexiant/concerto/wizard/server_plans"
)

func initLogging(lvl log.Level) {
	log.SetOutput(os.Stderr)
	log.SetLevel(lvl)
}

var ServerCommands = []cli.Command{
	{
		Name:  "firewall",
		Usage: "Manages Firewall Policies within a Host",
		Subcommands: append(
			firewall.SubCommands(),
		),
	},
	{
		Name:  "scripts",
		Usage: "Manages Execution Scripts within a Host",
		Subcommands: append(
			dispatcher.SubCommands(),
		),
	},
	{
		Name:   "converge",
		Usage:  "Converges Host to original Blueprint",
		Action: converge.CmbConverge,
	},
}

var BlueprintCommands = []cli.Command{
	{
		Name:  "scripts",
		Usage: "Allow the user to manage the scripts they want to run on the servers",
		Subcommands: append(
			scripts.SubCommands(),
		),
	},
	{
		Name:  "services",
		Usage: "Provides information on services",
		Subcommands: append(
			services.SubCommands(),
		),
	},
	{
		Name:  "templates",
		Usage: "Provides information on templates",
		Subcommands: append(
			templates.SubCommands(),
		),
	},
}

var CloudCommands = []cli.Command{
	{
		Name:  "workspaces",
		Usage: "Provides information on workspaces",
		Subcommands: append(
			workspaces.SubCommands(),
		),
	},
	{
		Name:  "servers",
		Usage: "Provides information on servers",
		Subcommands: append(
			servers.SubCommands(),
		),
	},
	{
		Name:  "generic_images",
		Usage: "Provides information on generic images",
		Subcommands: append(
			generic_images.SubCommands(),
		),
	},
	{
		Name:  "ssh_profiles",
		Usage: "Provides information on SSH profiles",
		Subcommands: append(
			ssh_profiles.SubCommands(),
		),
	},
	{
		Name:  "cloud_providers",
		Usage: "Provides information on cloud providers",
		Subcommands: append(
			providers.SubCommands(),
		),
	},
	{
		Name:  "server_plans",
		Usage: "Provides information on server plans",
		Subcommands: append(
			server_plan.SubCommands(),
		),
	},
	{
		Name:  "saas_providers",
		Usage: "Provides information about SAAS providers",
		Subcommands: append(
			saas_providers.SubCommands(),
		),
	},
}

var NetCommands = []cli.Command{
	{
		Name:  "firewall_profiles",
		Usage: "Provides information about firewall profiles",
		Subcommands: append(
			firewall_profiles.SubCommands(),
		),
	},
	{
		Name:  "load_balancers",
		Usage: "Provides information about load balancers",
		Subcommands: append(
			load_balancers.SubCommands(),
		),
	},
}

var SettingsCommands = []cli.Command{
	{
		Name:  "cloud_accounts",
		Usage: "Provides information about cloud accounts",
		Subcommands: append(
			cloud_accounts.SubCommands(),
		),
	},
	{
		Name:  "reports",
		Usage: "Provides information about reports",
		Subcommands: append(
			reports.SubCommands(),
		),
	},
	{
		Name:  "saas_accounts",
		Usage: "Provides information about SaaS accounts",
		Subcommands: append(
			saas_accounts.SubCommands(),
		),
	},
}

var WizardCommands = []cli.Command{
	{
		Name:  "apps",
		Usage: "Provides information about apps",
		Subcommands: append(
			apps.SubCommands(),
		),
	},
	{
		Name:  "cloud_providers",
		Usage: "Provides information about cloud providers",
		Subcommands: append(
			cloud_providers.SubCommands(),
		),
	},
	{
		Name:  "locations",
		Usage: "Provides information about locations",
		Subcommands: append(
			locations.SubCommands(),
		),
	},
	{
		Name:  "server_plans",
		Usage: "Provides information about server plans",
		Subcommands: append(
			server_plans.SubCommands(),
		),
	},
}

var ClientCommands = []cli.Command{
	{
		Name:      "nodes",
		ShortName: "no",
		Usage:     "Manages Docker Nodes",
		Subcommands: append(
			node.SubCommands(),
		),
	},
	{
		Name:      "cluster",
		ShortName: "clu",
		Usage:     "Manages a Kubernetes Cluster",
		Subcommands: append(
			cluster.SubCommands(),
		),
	},
	{
		Name:      "reports",
		ShortName: "rep",
		Usage:     "Provides historical uptime of servers",
		Subcommands: append(
			admin.SubCommands(),
		),
	},
	{
		Name:      "events",
		ShortName: "ev",
		Usage:     "Events allow the user to track their actions and the state of their servers",
		Subcommands: append(
			audit.SubCommands(),
		),
	},

	{
		Name:      "blueprint",
		ShortName: "bl",
		Usage:     "Manages blueprint commands for scripts, services and templates",
		Subcommands: append(
			BlueprintCommands,
		),
	},
	{
		Name:      "cloud",
		ShortName: "clo",
		Usage:     "Manages cloud related commands for workspaces, servers, generic images, ssh profiles, cloud providers, server plans and Saas providers",
		Subcommands: append(
			CloudCommands,
		),
	},
	{
		Name:      "dns_domains",
		ShortName: "dns",
		Usage:     "Provides information about DNS records",
		Subcommands: append(
			dns.SubCommands(),
		),
	},
	{
		Name:      "licensee_reports",
		ShortName: "lic",
		Usage:     "Provides information about licensee reports",
		Subcommands: append(
			licensee.SubCommands(),
		),
	},
	{
		Name:      "network",
		ShortName: "net",
		Usage:     "Manages network related commands for firewall profiles and load balancers",
		Subcommands: append(
			NetCommands,
		),
	},
	{
		Name:      "settings",
		ShortName: "set",
		Usage:     "Provides settings for cloud and Saas accounts as well as reports",
		Subcommands: append(
			SettingsCommands,
		),
	},
	{
		Name:      "wizard",
		ShortName: "wiz",
		Usage:     "Manages wizard related commands for apps, locations, cloud providers, server plans",
		Subcommands: append(
			WizardCommands,
		),
	},
}

func cmdNotFound(c *cli.Context, command string) {
	log.Fatalf(
		"%s: '%s' is not a %s command. See '%s --help'.",
		c.App.Name,
		command,
		c.App.Name,
		c.App.Name,
	)
}

func checkError(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func isUserCertificate(filename string) bool {
	if utils.Exists(filename) {
		data, err := ioutil.ReadFile(filename)
		checkError(err)
		block, _ := pem.Decode(data)

		cert, err := x509.ParseCertificate(block.Bytes)
		checkError(err)

		if len(cert.Subject.OrganizationalUnit) > 0 {
			if cert.Subject.OrganizationalUnit[0] == "Users" {
				return true

			}
		}
	}
	return false
}

func main() {

	for _, f := range os.Args {
		if f == "-D" || f == "--debug" || f == "-debug" {
			os.Setenv("DEBUG", "1")
			initLogging(log.DebugLevel)
		}
	}

	app := cli.NewApp()
	app.Name = path.Base(os.Args[0])
	app.Author = "Concerto Contributors"
	app.Email = "https://github.com/flexiant/concerto"

	app.CommandNotFound = cmdNotFound
	app.Usage = "Manages comunication between Host and Concerto Platform"
	app.Version = utils.VERSION

	if isUserCertificate(filepath.Join(utils.GetConcertoDir(), "ssl", "cert.crt")) {
		app.Commands = ClientCommands
	} else {
		app.Commands = ServerCommands
	}

	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "debug, D",
			Usage: "Enable debug mode",
		},
		cli.StringFlag{
			EnvVar: "CONCERTO_CA_CERT",
			Name:   "ca-cert",
			Usage:  "CA to verify remotes against",
			Value:  filepath.Join(utils.GetConcertoDir(), "ssl", "ca_cert.pem"),
		},
		cli.StringFlag{
			EnvVar: "CONCERTO_CLIENT_CERT",
			Name:   "client-cert",
			Usage:  "Client cert to use for Concerto",
			Value:  filepath.Join(utils.GetConcertoDir(), "ssl", "cert.crt"),
		},
		cli.StringFlag{
			EnvVar: "CONCERTO_CLIENT_KEY",
			Name:   "client-key",
			Usage:  "Private key used in client Concerto auth",
			Value:  filepath.Join(utils.GetConcertoDir(), "ssl", "/private/cert.key"),
		},
		cli.StringFlag{
			EnvVar: "CONCERTO_CONFIG",
			Name:   "concerto-config",
			Usage:  "Concerto Config File",
			Value:  filepath.Join(utils.GetConcertoDir(), "client.xml"),
		},
		cli.StringFlag{
			EnvVar: "CONCERTO_ENDPOINT",
			Name:   "concerto-endpoint",
			Usage:  "Concerto Endpoint",
			Value:  os.Getenv("CONCERTO_ENDPOINT"),
		},
	}

	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"github.com/178inaba/nico"
	"github.com/howeyc/gopass"
	homedir "github.com/mitchellh/go-homedir"
)

const (
	defaultSessionFilePath = "lv-barrage/session"
	hbIfseetnoComment      = "/hb ifseetno "
)

var (
	isAnonymous  = flag.Bool("a", false, "Post anonymous user (184)")
	commentColor = flag.String("c", "", "Comment color")
	isPostOnce   = flag.Bool("o", false, "Post once")
)

func main() {
	log.SetFlags(0)
	log.SetPrefix(fmt.Sprintf("%s: ", os.Args[0]))
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "usage: %s [-a] [-c <comment_color>] [-o] <live_id | live_url> <comment>\n", os.Args[0])
		flag.PrintDefaults()
	}
	flag.Parse()
	os.Exit(run())
}

func run() int {
	args := flag.Args()
	if len(args) != 2 {
		flag.Usage()
		return 1
	}
	liveID, err := nico.FindLiveID(args[0])
	if err != nil {
		log.Print(err)
		return 1
	}
	comment := args[1]

	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, os.Interrupt)
	ctx, cancel := context.WithCancel(context.Background())
	go func() {
		<-sigCh
		cancel()
	}()

	sessionFilePath, err := getSessionFilePath()
	if err != nil {
		log.Print(err)
		return 1
	}

	c, err := getClientWithSession(ctx, sessionFilePath)
	if err != nil {
		log.Print(err)
		return 1
	}

	if err := barrage(ctx, c, liveID, comment); err != nil {
		log.Print(err)
		return 1
	}

	return 0
}

func barrage(ctx context.Context, c *nico.Client, liveID, comment string) error {
	continueDuration := 10 * time.Second
	mail := nico.Mail{CommentColor: *commentColor}
	if *isAnonymous {
		mail.Is184 = true
	}
	for {
		select {
		case <-ctx.Done():
			// Signal interrupt.
			return nil
		default:
		}
		lc, err := c.MakeLiveClient(ctx, liveID)
		if err != nil {
			if pse, ok := err.(nico.PlayerStatusError); ok {
				switch pse.Code {
				case nico.PlayerStatusErrorCodeFull:
					fmt.Println("Continue: Seat is full")
					continue
				case nico.PlayerStatusErrorCodeRequireCommunityMember:
					if err := followCommunityFromLiveID(ctx, c, liveID); err != nil {
						return err
					}
					continue
				}
			}
			return err
		}
		ch, err := lc.StreamingComment(ctx, 0)
		if err != nil {
			return err
		}
		errCh := make(chan error)
		chatResultCh := make(chan *nico.ChatResult)
		go func() {
			var continueCnt int
			for {
				if err := lc.PostComment(ctx, comment, mail); err != nil {
					log.Print(err)
					errCh <- err
					return
				}
				cr := <-chatResultCh
				if *isPostOnce {
					errCh <- errors.New("post once")
					return
				}
				if cr.Status != 0 {
					continueCnt++
					if continueCnt > 1 {
						continueDuration += 10 * time.Second
					}
					time.Sleep(continueDuration)
				} else {
					continueCnt = 0
				}
				time.Sleep(5 * time.Second)
			}
		}()
		for ci := range ch {
			var isBreak bool
			select {
			case err := <-errCh:
				log.Print(err)
				isBreak = true
			default:
			}
			if isBreak {
				if *isPostOnce {
					return nil
				}
				break
			}
			switch com := ci.(type) {
			case *nico.Thread:
				fmt.Printf("%#v\n", com)
			case *nico.ChatResult:
				chatResultCh <- com
				fmt.Printf("%#v\n", com)
			case *nico.Chat:
				if strings.Contains(com.Comment, hbIfseetnoComment) {
					continue
				}
				fmt.Println(com.Comment)
			}
		}
	}
}

func followCommunityFromLiveID(ctx context.Context, c *nico.Client, liveID string) error {
	comID, err := c.GetCommunityIDFromLiveID(ctx, liveID)
	if err != nil {
		return err
	}
	if err := c.FollowCommunity(ctx, comID); err != nil {
		return err
	}
	return nil
}

func getSessionFilePath() (string, error) {
	if runtime.GOOS == "windows" {
		return filepath.Join(os.Getenv("APPDATA"), defaultSessionFilePath), nil
	}
	home, err := homedir.Dir()
	if err != nil {
		return "", err
	}
	return filepath.Join(home, ".config", defaultSessionFilePath), nil
}

func getClientWithSession(ctx context.Context, sessionFilePath string) (*nico.Client, error) {
	c := nico.NewClient()
	userSession, err := getSession(sessionFilePath)
	if err != nil {
		mail, password, err := prompt(ctx)
		if err != nil {
			return nil, err
		}
		userSession, err = c.Login(ctx, mail, password)
		if err != nil {
			return nil, err
		}

		if err := saveSession(userSession, sessionFilePath); err != nil {
			return nil, err
		}
	} else {
		c.UserSession = userSession
	}
	return c, nil
}

func prompt(ctx context.Context) (string, string, error) {
	// Login mail address from stdin.
	fmt.Print("Mail: ")
	ch := make(chan string)
	go func() {
		var s string
		fmt.Scanln(&s)
		ch <- s
	}()
	var mail string
	select {
	case <-ctx.Done():
		return "", "", ctx.Err()
	case mail = <-ch:
	}

	// Password from stdin.
	fmt.Print("Password: ")
	pBytes, err := gopass.GetPasswd()
	if err != nil {
		return "", "", err
	}

	return mail, string(pBytes), nil
}

func getSession(fp string) (string, error) {
	f, err := os.Open(fp)
	if err != nil {
		return "", err
	}
	defer f.Close()

	bs, err := ioutil.ReadAll(f)
	if err != nil {
		return "", err
	}
	return string(bs), nil
}

func saveSession(session, sessionFilePath string) error {
	if err := os.MkdirAll(filepath.Dir(sessionFilePath), 0700); err != nil {
		return err
	}
	if err := ioutil.WriteFile(sessionFilePath, []byte(session), 0600); err != nil {
		return err
	}
	return nil
}
<commit_msg>Add getMail<commit_after>package main

import (
	"context"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"github.com/178inaba/nico"
	"github.com/howeyc/gopass"
	homedir "github.com/mitchellh/go-homedir"
)

const (
	defaultSessionFilePath = "lv-barrage/session"
	hbIfseetnoComment      = "/hb ifseetno "
)

var (
	isAnonymous  = flag.Bool("a", false, "Post anonymous user (184)")
	commentColor = flag.String("c", "", "Comment color")
	isPostOnce   = flag.Bool("o", false, "Post once")
)

func main() {
	log.SetFlags(0)
	log.SetPrefix(fmt.Sprintf("%s: ", os.Args[0]))
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "usage: %s [-a] [-c <comment_color>] [-o] <live_id | live_url> <comment>\n", os.Args[0])
		flag.PrintDefaults()
	}
	flag.Parse()
	os.Exit(run())
}

func run() int {
	args := flag.Args()
	if len(args) != 2 {
		flag.Usage()
		return 1
	}
	liveID, err := nico.FindLiveID(args[0])
	if err != nil {
		log.Print(err)
		return 1
	}
	comment := args[1]

	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, os.Interrupt)
	ctx, cancel := context.WithCancel(context.Background())
	go func() {
		<-sigCh
		cancel()
	}()

	sessionFilePath, err := getSessionFilePath()
	if err != nil {
		log.Print(err)
		return 1
	}

	c, err := getClientWithSession(ctx, sessionFilePath)
	if err != nil {
		log.Print(err)
		return 1
	}

	if err := barrage(ctx, c, liveID, comment); err != nil {
		log.Print(err)
		return 1
	}

	return 0
}

func barrage(ctx context.Context, c *nico.Client, liveID, comment string) error {
	continueDuration := 10 * time.Second
	mail := getMail()
	for {
		select {
		case <-ctx.Done():
			// Signal interrupt.
			return nil
		default:
		}
		lc, err := c.MakeLiveClient(ctx, liveID)
		if err != nil {
			if pse, ok := err.(nico.PlayerStatusError); ok {
				switch pse.Code {
				case nico.PlayerStatusErrorCodeFull:
					fmt.Println("Continue: Seat is full")
					continue
				case nico.PlayerStatusErrorCodeRequireCommunityMember:
					if err := followCommunityFromLiveID(ctx, c, liveID); err != nil {
						return err
					}
					continue
				}
			}
			return err
		}
		ch, err := lc.StreamingComment(ctx, 0)
		if err != nil {
			return err
		}
		errCh := make(chan error)
		chatResultCh := make(chan *nico.ChatResult)
		go func() {
			var continueCnt int
			for {
				if err := lc.PostComment(ctx, comment, mail); err != nil {
					log.Print(err)
					errCh <- err
					return
				}
				cr := <-chatResultCh
				if *isPostOnce {
					errCh <- errors.New("post once")
					return
				}
				if cr.Status != 0 {
					continueCnt++
					if continueCnt > 1 {
						continueDuration += 10 * time.Second
					}
					time.Sleep(continueDuration)
				} else {
					continueCnt = 0
				}
				time.Sleep(5 * time.Second)
			}
		}()
		for ci := range ch {
			var isBreak bool
			select {
			case err := <-errCh:
				log.Print(err)
				isBreak = true
			default:
			}
			if isBreak {
				if *isPostOnce {
					return nil
				}
				break
			}
			switch com := ci.(type) {
			case *nico.Thread:
				fmt.Printf("%#v\n", com)
			case *nico.ChatResult:
				chatResultCh <- com
				fmt.Printf("%#v\n", com)
			case *nico.Chat:
				if strings.Contains(com.Comment, hbIfseetnoComment) {
					continue
				}
				fmt.Println(com.Comment)
			}
		}
	}
}

func getMail() nico.Mail {
	mail := nico.Mail{CommentColor: *commentColor}
	if *isAnonymous {
		mail.Is184 = true
	}
	return mail
}

func followCommunityFromLiveID(ctx context.Context, c *nico.Client, liveID string) error {
	comID, err := c.GetCommunityIDFromLiveID(ctx, liveID)
	if err != nil {
		return err
	}
	if err := c.FollowCommunity(ctx, comID); err != nil {
		return err
	}
	return nil
}

func getSessionFilePath() (string, error) {
	if runtime.GOOS == "windows" {
		return filepath.Join(os.Getenv("APPDATA"), defaultSessionFilePath), nil
	}
	home, err := homedir.Dir()
	if err != nil {
		return "", err
	}
	return filepath.Join(home, ".config", defaultSessionFilePath), nil
}

func getClientWithSession(ctx context.Context, sessionFilePath string) (*nico.Client, error) {
	c := nico.NewClient()
	userSession, err := getSession(sessionFilePath)
	if err != nil {
		mail, password, err := prompt(ctx)
		if err != nil {
			return nil, err
		}
		userSession, err = c.Login(ctx, mail, password)
		if err != nil {
			return nil, err
		}

		if err := saveSession(userSession, sessionFilePath); err != nil {
			return nil, err
		}
	} else {
		c.UserSession = userSession
	}
	return c, nil
}

func prompt(ctx context.Context) (string, string, error) {
	// Login mail address from stdin.
	fmt.Print("Mail: ")
	ch := make(chan string)
	go func() {
		var s string
		fmt.Scanln(&s)
		ch <- s
	}()
	var mail string
	select {
	case <-ctx.Done():
		return "", "", ctx.Err()
	case mail = <-ch:
	}

	// Password from stdin.
	fmt.Print("Password: ")
	pBytes, err := gopass.GetPasswd()
	if err != nil {
		return "", "", err
	}

	return mail, string(pBytes), nil
}

func getSession(fp string) (string, error) {
	f, err := os.Open(fp)
	if err != nil {
		return "", err
	}
	defer f.Close()

	bs, err := ioutil.ReadAll(f)
	if err != nil {
		return "", err
	}
	return string(bs), nil
}

func saveSession(session, sessionFilePath string) error {
	if err := os.MkdirAll(filepath.Dir(sessionFilePath), 0700); err != nil {
		return err
	}
	if err := ioutil.WriteFile(sessionFilePath, []byte(session), 0600); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>// HTTP/2 web server with built-in support for Lua, Markdown, GCSS, Amber and JSX.
package main

import (
	"errors"
	"fmt"
	log "github.com/sirupsen/logrus"
	"io/ioutil"
	internallog "log"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"runtime/pprof"
	"strings"
	"time"

	"github.com/xyproto/unzip"
	"github.com/yuin/gopher-lua"
)

const (
	versionString         = "Algernon 0.83"
	description           = "HTTP/2 Web Server"
	specialServerFilename = "server.lua"
)

var (
	// For convenience. Set in the main function.
	serverHost      string
	dbName          string
	refreshDuration time.Duration
)

func main() {
	var err error

	// TODO: Benchmark to see if runtime.NumCPU() * X scales better.
	runtime.GOMAXPROCS(runtime.NumCPU())

	// Temporary directory that might be used for logging, databases or file extraction
	serverTempDir, err := ioutil.TempDir("", "algernon")
	if err != nil {
		log.Fatalln(err)
	}
	defer os.RemoveAll(serverTempDir)

	// Set several configuration variables, based on the given flags and arguments
	serverHost = handleFlags(serverTempDir)

	// Version
	if showVersion {
		if !quietMode {
			fmt.Println(versionString)
		}
		os.Exit(0)
	}

	// Console output
	if !quietMode {
		fmt.Println(banner())
	}

	// CPU profiling
	if profileCPU != "" {
		f, err := os.Create(profileCPU)
		if err != nil {
			log.Fatal(err)
		}
		go func() {
			log.Info("Profiling CPU")
			pprof.StartCPUProfile(f)
		}()
		atShutdown(func() {
			pprof.StopCPUProfile()
			log.Info("Done profiling")
		})
	}

	// Memory profiling at server shutdown
	if profileMem != "" {
		atShutdown(func() {
			f, err := os.Create(profileMem)
			if err != nil {
				log.Fatal(err)
			}
			log.Info("Writing heap profile to ", profileMem)
			pprof.WriteHeapProfile(f)
			f.Close()
		})
	}

	// Dividing line between the banner and output from any of the configuration scripts
	if len(serverConfigurationFilenames) > 0 && !quietMode {
		fmt.Println("--------------------------------------- - - · ·")
	}

	// Request handlers
	mux := http.NewServeMux()

	// Read mime data from the system, if available
	initializeMime()

	// Check if the given directory really is a directory
	if !isDir(serverDir) {
		// Possibly a file
		filename := serverDir
		// Check if the file exists
		if exists(filename) {
			// Switch based on the lowercase filename extension
			switch strings.ToLower(filepath.Ext(filename)) {
			case ".md", ".markdown":
				// Serve the given Markdown file as a static HTTP server
				serveStaticFile(filename, defaultWebColonPort)
				return
			case ".zip", ".alg":
				// Assume this to be a compressed Algernon application
				err := unzip.Extract(filename, serverTempDir)
				if err != nil {
					log.Fatalln(err)
				}
				// Use the directory where the file was extracted as the server directory
				serverDir = serverTempDir
				// If there is only one directory there, assume it's the
				// directory of the newly extracted ZIP file.
				if filenames := getFilenames(serverDir); len(filenames) == 1 {
					fullPath := filepath.Join(serverDir, filenames[0])
					if isDir(fullPath) {
						// Use this as the server directory instead
						serverDir = fullPath
					}
				}
				// If there are server configuration files in the extracted
				// directory, register them.
				for _, filename := range serverConfigurationFilenames {
					configFilename := filepath.Join(serverDir, filename)
					if exists(configFilename) {
						serverConfigurationFilenames = append(serverConfigurationFilenames, configFilename)
					}
				}
				// Disregard all configuration files from the current directory
				// (filenames without a path separator), since we are serving a
				// ZIP file.
				for i, filename := range serverConfigurationFilenames {
					if strings.Count(filepath.ToSlash(filename), "/") == 0 {
						// Remove the filename from the slice
						serverConfigurationFilenames = append(serverConfigurationFilenames[:i], serverConfigurationFilenames[i+1:]...)
					}
				}
			default:
				singleFileMode = true
			}
		} else {
			fatalExit(errors.New("File does not exist: " + filename))
		}
	}

	// Make a few changes to the defaults if we are serving a single file
	if singleFileMode {
		debugMode = true
		serveJustHTTP = true
	}

	// Connect to a database and retrieve a Permissions struct
	perm := mustAquirePermissions()

	// Lua LState pool
	luapool := &lStatePool{saved: make([]*lua.LState, 0, 4)}
	atShutdown(func() {
		luapool.Shutdown()
	})

	// TODO: save repl history + close luapool + close logs ++ at shutdown

	// Create a cache struct for reading files (contains functions that can
	// be used for reading files, also when caching is disabled).
	// The final argument is for compressing with "fast" instead of "best".
	cache := newFileCache(cacheSize, cacheCompression, cacheMaxEntitySize)

	if singleFileMode && filepath.Base(serverDir) == specialServerFilename {
		luaServerFilename = serverDir
		serverDir = filepath.Dir(serverDir)
		singleFileMode = false
	}

	// Log to a file as JSON, if a log file has been specified
	if serverLogFile != "" {
		f, err := os.OpenFile(serverLogFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, defaultPermissions)
		if err != nil {
			log.Error("Could not log to", serverLogFile)
			fatalExit(err)
		}
		log.SetFormatter(&log.JSONFormatter{})
		log.SetOutput(f)
	} else if quietMode {
		// If quiet mode is enabled and no log file has been specified, disable logging
		log.SetOutput(ioutil.Discard)
	}

	if quietMode {
		os.Stdout.Close()
		os.Stderr.Close()
	}

	// Read server configuration script, if present.
	// The scripts may change global variables.
	var ranConfigurationFilenames []string
	for _, filename := range serverConfigurationFilenames {
		if exists(filename) {
			if verboseMode {
				fmt.Println("Running configuration file: " + filename)
			}
			if err := runConfiguration(filename, perm, luapool, cache, mux, false); err != nil {
				log.Error("Could not use configuration script: " + filename)
				fatalExit(err)
			}
			ranConfigurationFilenames = append(ranConfigurationFilenames, filename)
		}
	}
	// Only keep the active ones. Used when outputting server information.
	serverConfigurationFilenames = ranConfigurationFilenames

	// Run the standalone Lua server, if specified
	if luaServerFilename != "" {
		// Run the Lua server file and set up handlers
		if verboseMode {
			fmt.Println("Running Lua Server File")
		}
		if err := runConfiguration(luaServerFilename, perm, luapool, cache, mux, true); err != nil {
			log.Error("Error in Lua server script: " + luaServerFilename)
			fatalExit(err)
		}
	} else {
		// Register HTTP handler functions
		registerHandlers(mux, "/", serverDir, perm, luapool, cache)
	}

	// Set the values that has not been set by flags nor scripts
	// (and can be set by both)
	ranServerReadyFunction := finalConfiguration(serverHost)

	// If no configuration files were being ran succesfully,
	// output basic server information.
	if len(serverConfigurationFilenames) == 0 {
		if !quietMode {
			fmt.Println(serverInfo())
		}
		ranServerReadyFunction = true
	}

	// Dividing line between the banner and output from any of the
	// configuration scripts. Marks the end of the configuration output.
	if ranServerReadyFunction && !quietMode {
		fmt.Println("--------------------------------------- - - · ·")
	}

	// Direct internal logging elsewhere
	internalLogFile, err := os.Open(internalLogFilename)
	defer internalLogFile.Close()

	if err != nil {
		// Could not open the internalLogFilename filename, try using another filename
		internalLogFile, err = os.OpenFile("internal.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, defaultPermissions)
		atShutdown(func() {
			internalLogFile.Close()
		})
		if err != nil {
			fatalExit(fmt.Errorf("Could not write to %s nor %s.", internalLogFilename, "internal.log"))
		}
	}
	internallog.SetOutput(internalLogFile)

	// Serve filesystem events in the background.
	// Used for reloading pages when the sources change.
	// Can also be used when serving a single file.
	if autoRefreshMode {
		refreshDuration, err = time.ParseDuration(eventRefresh)
		if err != nil {
			log.Warn(fmt.Sprintf("%s is an invalid duration. Using %s instead.", eventRefresh, defaultEventRefresh))
			// Ignore the error, since defaultEventRefresh is a constant and must be parseable
			refreshDuration, _ = time.ParseDuration(defaultEventRefresh)
		}
		if autoRefreshDir != "" {
			// Only watch the autoRefreshDir, recursively
			EventServer(eventAddr, defaultEventPath, autoRefreshDir, refreshDuration, "*")
		} else {
			// Watch everything in the server directory, recursively
			EventServer(eventAddr, defaultEventPath, serverDir, refreshDuration, "*")
		}
	}

	// For communicating to and from the REPL
	ready := make(chan bool) // for when the server is up and running
	done := make(chan bool)  // for when the user wish to quit the server

	// The Lua REPL
	if !serverMode {
		go REPL(perm, luapool, cache, ready, done)
	}

	conf := &algernonServerConfig{
		productionMode:      productionMode,
		serverHost:          serverHost,
		serverAddr:          serverAddr,
		serverCert:          serverCert,
		serverKey:           serverKey,
		serveJustHTTP:       serveJustHTTP,
		serveJustHTTP2:      serveJustHTTP2,
		shutdownTimeout:     10 * time.Second,
		internalLogFilename: internalLogFilename,
	}

	// Run the shutdown functions if graceful does not
	defer runShutdown()

	// Serve HTTP, HTTP/2 and/or HTTPS
	if err := serve(conf, mux, done, ready); err != nil {
		fatalExit(err)
	}
}
<commit_msg>Better CPU and memory profile info messages<commit_after>// HTTP/2 web server with built-in support for Lua, Markdown, GCSS, Amber and JSX.
package main

import (
	"errors"
	"fmt"
	log "github.com/sirupsen/logrus"
	"io/ioutil"
	internallog "log"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"runtime/pprof"
	"strings"
	"time"

	"github.com/xyproto/unzip"
	"github.com/yuin/gopher-lua"
)

const (
	versionString         = "Algernon 0.83"
	description           = "HTTP/2 Web Server"
	specialServerFilename = "server.lua"
)

var (
	// For convenience. Set in the main function.
	serverHost      string
	dbName          string
	refreshDuration time.Duration
)

func main() {
	var err error

	// TODO: Benchmark to see if runtime.NumCPU() * X scales better.
	runtime.GOMAXPROCS(runtime.NumCPU())

	// Temporary directory that might be used for logging, databases or file extraction
	serverTempDir, err := ioutil.TempDir("", "algernon")
	if err != nil {
		log.Fatalln(err)
	}
	defer os.RemoveAll(serverTempDir)

	// Set several configuration variables, based on the given flags and arguments
	serverHost = handleFlags(serverTempDir)

	// Version
	if showVersion {
		if !quietMode {
			fmt.Println(versionString)
		}
		os.Exit(0)
	}

	// Console output
	if !quietMode {
		fmt.Println(banner())
	}

	// CPU profiling
	if profileCPU != "" {
		f, err := os.Create(profileCPU)
		if err != nil {
			log.Fatal(err)
		}
		go func() {
			log.Info("Profiling CPU usage")
			pprof.StartCPUProfile(f)
		}()
		atShutdown(func() {
			pprof.StopCPUProfile()
			log.Info("Done profiling CPU usage")
		})
	}

	// Memory profiling at server shutdown
	if profileMem != "" {
		atShutdown(func() {
			f, err := os.Create(profileMem)
			defer f.Close()
			if err != nil {
				log.Fatal(err)
			}
			log.Info("Saving heap profile to ", profileMem)
			pprof.WriteHeapProfile(f)
		})
	}

	// Dividing line between the banner and output from any of the configuration scripts
	if len(serverConfigurationFilenames) > 0 && !quietMode {
		fmt.Println("--------------------------------------- - - · ·")
	}

	// Request handlers
	mux := http.NewServeMux()

	// Read mime data from the system, if available
	initializeMime()

	// Check if the given directory really is a directory
	if !isDir(serverDir) {
		// Possibly a file
		filename := serverDir
		// Check if the file exists
		if exists(filename) {
			// Switch based on the lowercase filename extension
			switch strings.ToLower(filepath.Ext(filename)) {
			case ".md", ".markdown":
				// Serve the given Markdown file as a static HTTP server
				serveStaticFile(filename, defaultWebColonPort)
				return
			case ".zip", ".alg":
				// Assume this to be a compressed Algernon application
				err := unzip.Extract(filename, serverTempDir)
				if err != nil {
					log.Fatalln(err)
				}
				// Use the directory where the file was extracted as the server directory
				serverDir = serverTempDir
				// If there is only one directory there, assume it's the
				// directory of the newly extracted ZIP file.
				if filenames := getFilenames(serverDir); len(filenames) == 1 {
					fullPath := filepath.Join(serverDir, filenames[0])
					if isDir(fullPath) {
						// Use this as the server directory instead
						serverDir = fullPath
					}
				}
				// If there are server configuration files in the extracted
				// directory, register them.
				for _, filename := range serverConfigurationFilenames {
					configFilename := filepath.Join(serverDir, filename)
					if exists(configFilename) {
						serverConfigurationFilenames = append(serverConfigurationFilenames, configFilename)
					}
				}
				// Disregard all configuration files from the current directory
				// (filenames without a path separator), since we are serving a
				// ZIP file.
				for i, filename := range serverConfigurationFilenames {
					if strings.Count(filepath.ToSlash(filename), "/") == 0 {
						// Remove the filename from the slice
						serverConfigurationFilenames = append(serverConfigurationFilenames[:i], serverConfigurationFilenames[i+1:]...)
					}
				}
			default:
				singleFileMode = true
			}
		} else {
			fatalExit(errors.New("File does not exist: " + filename))
		}
	}

	// Make a few changes to the defaults if we are serving a single file
	if singleFileMode {
		debugMode = true
		serveJustHTTP = true
	}

	// Connect to a database and retrieve a Permissions struct
	perm := mustAquirePermissions()

	// Lua LState pool
	luapool := &lStatePool{saved: make([]*lua.LState, 0, 4)}
	atShutdown(func() {
		luapool.Shutdown()
	})

	// TODO: save repl history + close luapool + close logs ++ at shutdown

	// Create a cache struct for reading files (contains functions that can
	// be used for reading files, also when caching is disabled).
	// The final argument is for compressing with "fast" instead of "best".
	cache := newFileCache(cacheSize, cacheCompression, cacheMaxEntitySize)

	if singleFileMode && filepath.Base(serverDir) == specialServerFilename {
		luaServerFilename = serverDir
		serverDir = filepath.Dir(serverDir)
		singleFileMode = false
	}

	// Log to a file as JSON, if a log file has been specified
	if serverLogFile != "" {
		f, err := os.OpenFile(serverLogFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, defaultPermissions)
		if err != nil {
			log.Error("Could not log to", serverLogFile)
			fatalExit(err)
		}
		log.SetFormatter(&log.JSONFormatter{})
		log.SetOutput(f)
	} else if quietMode {
		// If quiet mode is enabled and no log file has been specified, disable logging
		log.SetOutput(ioutil.Discard)
	}

	if quietMode {
		os.Stdout.Close()
		os.Stderr.Close()
	}

	// Read server configuration script, if present.
	// The scripts may change global variables.
	var ranConfigurationFilenames []string
	for _, filename := range serverConfigurationFilenames {
		if exists(filename) {
			if verboseMode {
				fmt.Println("Running configuration file: " + filename)
			}
			if err := runConfiguration(filename, perm, luapool, cache, mux, false); err != nil {
				log.Error("Could not use configuration script: " + filename)
				fatalExit(err)
			}
			ranConfigurationFilenames = append(ranConfigurationFilenames, filename)
		}
	}
	// Only keep the active ones. Used when outputting server information.
	serverConfigurationFilenames = ranConfigurationFilenames

	// Run the standalone Lua server, if specified
	if luaServerFilename != "" {
		// Run the Lua server file and set up handlers
		if verboseMode {
			fmt.Println("Running Lua Server File")
		}
		if err := runConfiguration(luaServerFilename, perm, luapool, cache, mux, true); err != nil {
			log.Error("Error in Lua server script: " + luaServerFilename)
			fatalExit(err)
		}
	} else {
		// Register HTTP handler functions
		registerHandlers(mux, "/", serverDir, perm, luapool, cache)
	}

	// Set the values that has not been set by flags nor scripts
	// (and can be set by both)
	ranServerReadyFunction := finalConfiguration(serverHost)

	// If no configuration files were being ran succesfully,
	// output basic server information.
	if len(serverConfigurationFilenames) == 0 {
		if !quietMode {
			fmt.Println(serverInfo())
		}
		ranServerReadyFunction = true
	}

	// Dividing line between the banner and output from any of the
	// configuration scripts. Marks the end of the configuration output.
	if ranServerReadyFunction && !quietMode {
		fmt.Println("--------------------------------------- - - · ·")
	}

	// Direct internal logging elsewhere
	internalLogFile, err := os.Open(internalLogFilename)
	defer internalLogFile.Close()

	if err != nil {
		// Could not open the internalLogFilename filename, try using another filename
		internalLogFile, err = os.OpenFile("internal.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, defaultPermissions)
		atShutdown(func() {
			internalLogFile.Close()
		})
		if err != nil {
			fatalExit(fmt.Errorf("Could not write to %s nor %s.", internalLogFilename, "internal.log"))
		}
	}
	internallog.SetOutput(internalLogFile)

	// Serve filesystem events in the background.
	// Used for reloading pages when the sources change.
	// Can also be used when serving a single file.
	if autoRefreshMode {
		refreshDuration, err = time.ParseDuration(eventRefresh)
		if err != nil {
			log.Warn(fmt.Sprintf("%s is an invalid duration. Using %s instead.", eventRefresh, defaultEventRefresh))
			// Ignore the error, since defaultEventRefresh is a constant and must be parseable
			refreshDuration, _ = time.ParseDuration(defaultEventRefresh)
		}
		if autoRefreshDir != "" {
			// Only watch the autoRefreshDir, recursively
			EventServer(eventAddr, defaultEventPath, autoRefreshDir, refreshDuration, "*")
		} else {
			// Watch everything in the server directory, recursively
			EventServer(eventAddr, defaultEventPath, serverDir, refreshDuration, "*")
		}
	}

	// For communicating to and from the REPL
	ready := make(chan bool) // for when the server is up and running
	done := make(chan bool)  // for when the user wish to quit the server

	// The Lua REPL
	if !serverMode {
		go REPL(perm, luapool, cache, ready, done)
	}

	conf := &algernonServerConfig{
		productionMode:      productionMode,
		serverHost:          serverHost,
		serverAddr:          serverAddr,
		serverCert:          serverCert,
		serverKey:           serverKey,
		serveJustHTTP:       serveJustHTTP,
		serveJustHTTP2:      serveJustHTTP2,
		shutdownTimeout:     10 * time.Second,
		internalLogFilename: internalLogFilename,
	}

	// Run the shutdown functions if graceful does not
	defer runShutdown()

	// Serve HTTP, HTTP/2 and/or HTTPS
	if err := serve(conf, mux, done, ready); err != nil {
		fatalExit(err)
	}
}
<|endoftext|>


<commit_before>// Number One rule: it's compiling it's working, no tests needed
// Copyright AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
// AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
// AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
// AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

// +build ignore

package main

import (
  ui "github.com/gizak/termui"
  "time"
  "strconv"
  "net/http"
  "io/ioutil"
  "encoding/json"
  "strings"
  "sort"
  "fmt"
  "math"
  "flag"
  "log"
  "errors"
)

type LangStatistic struct {
  Level string `json:"level"`
  Points float64 `json:"points"`
}

type Language struct {
  Name string
  Points float64
  Level int
  Percent float64
}

type PlatformStatistic struct {
  PercentWork float64 `json:"percent_work"`
  Points float64 `json:"points"`
  Time float64 `json:"time"`
}

type Platform struct {
  Name string
  PercentWork float64
  Points float64
  Time float64
}

type UserStatistic struct {
  CurrentLanguage string `json:"current_language"`
  FocusLevel string `json:"focus_level"`
  FocusPoints float64 `json:"focus_points"`
  Level string `json:"level"`
  MaxStreak float64 `json:"max_streak"`
  Name string `json:"name"`
  ProgrammingNow bool `json:"programming_now"`
  StreakingNow bool `json:"streaking_now"`
  TimeSpent float64 `json:"time_spent"`
  TotalDaysCoded float64 `json:"total_days_coded"`
  TotalFlowStates float64 `json:"total_flow_states"`
  Platforms map[string]PlatformStatistic `json:"platforms"`
  Languages map[string]LangStatistic `json:"languages"`
}

type ByLevel []Language
func (v ByLevel) Len() int { return len(v) }
func (v ByLevel) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
func (v ByLevel) Less(i, j int) bool {
  if v[i].Level == v[j].Level {
    if v[i].Points == v[j].Points {
      return v[i].Name > v[j].Name
    } else {
      return v[i].Points > v[j].Points
    }

  } else {
    return v[i].Level > v[j].Level
  }
}

type PlatformByPoints []Platform
func (v PlatformByPoints) Len() int { return len(v) }
func (v PlatformByPoints) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
func (v PlatformByPoints) Less(i, j int) bool {
  if v[i].Points == v[j].Points {
    if v[i].Time == v[j].Time {
      return v[i].Name > v[j].Name
    } else {
      return v[i].Time > v[j].Time
    }
  } else {
    return v[i].Points > v[j].Points
  }
}

type Level struct {
  Number int
  Percent float64
}

func ParseLevel(strLevel string) (Level, error) {
  splited := strings.Split(strLevel, ".")
  level, err := strconv.Atoi(splited[0])
  if err != nil {
    return Level{}, err
  }
  percent, err := strconv.ParseFloat(splited[1], 64)
  if err != nil {
    return Level{}, err
  }
  return Level{level, percent}, nil
}

func HandleMeLikeOneOfYourFrenchGirls(err error) {
  parUser := ui.NewPar(err.Error())
  parUser.Height = 3
  parUser.Width = 50
  parUser.TextFgColor = ui.ColorWhite
  parUser.Border.Label = "Erro acontece nada ocorre feijoada"
  parUser.Border.FgColor = ui.ColorCyan

  ui.Body.AddRows(
      ui.NewRow(ui.NewCol(12, 0, parUser)))
}

func main() {
  // yeah, if there's no username you'll see my profile :3
  var username string
  var numberOfLanguages int
  flag.StringVar(&username, "username", "schleumer", "your codeivate username")
  flag.IntVar(&numberOfLanguages, "len", 10, "number of languages to display")
  flag.Parse()

  err := ui.Init()
  if err != nil {
    panic(err)
  }
  defer ui.Close()

  ui.UseTheme("helloworld")

  done := make(chan bool)
  redraw := make(chan bool)
  error := make(chan string)

  ui.Body.Align()

  update := func () {
    for {
      // restart body
      ui.Body = ui.NewGrid()
      ui.Body.Width = ui.TermWidth()

      client := &http.Client{}
      req, err := http.NewRequest("GET", fmt.Sprintf("http://codeivate.com/users/%s.json", username), nil)
      req.Close = true
      req.Header.Set("Content-Type", "application/json")
      req.Header.Set("User-Agent", "NOTICE ME SENPAI v0.1a")
      resp, err := client.Do(req)

      if err != nil {
        HandleMeLikeOneOfYourFrenchGirls(err)
        redraw <- true
        time.Sleep(time.Second * 5)
        continue
      }

      body, err := ioutil.ReadAll(resp.Body)
      if err != nil {
        HandleMeLikeOneOfYourFrenchGirls(err)
        redraw <- true
        time.Sleep(time.Second * 5)
        continue
      }

      var statistic UserStatistic
      err = json.Unmarshal(body, &statistic)
      if err != nil {
        HandleMeLikeOneOfYourFrenchGirls(errors.New(fmt.Sprintf("Error on unmarshaling, probably the user %s doesn't exists", username)))
        redraw <- true
        time.Sleep(time.Second * 60)
        continue
      }

      userLevel, err := ParseLevel(statistic.Level)
      if err != nil {
        HandleMeLikeOneOfYourFrenchGirls(err)
        redraw <- true
        time.Sleep(time.Second * 5)
        continue
      }

      // i have no idea what i'm doing, but it's fucking hardcore
      hours := math.Floor(statistic.TimeSpent / 3600)
      minutes := math.Floor((statistic.TimeSpent - (hours * 3600)) / 60)

      parUser := ui.NewPar(fmt.Sprintf("Level: %d - Percent: %.0f - Time: %.0f hours %.0f minutes - Current Language: %s", userLevel.Number, userLevel.Percent, hours, minutes, statistic.CurrentLanguage))
      parUser.Height = 3
      parUser.Width = 50
      parUser.TextFgColor = ui.ColorWhite
      parUser.Border.Label = "User Info"
      parUser.Border.FgColor = ui.ColorCyan

      ui.Body.AddRows(
          ui.NewRow(ui.NewCol(12, 0, parUser)))

      var platformsContent []string

      var platforms []Platform

      for name, platform := range statistic.Platforms {
        platforms = append(platforms, Platform{name, platform.PercentWork, platform.Points, platform.Time})
      }

      sort.Sort(PlatformByPoints(platforms))

      for _, platform := range platforms {
        hours := math.Floor(platform.Time / 3600)
        minutes := math.Floor((platform.Time - (hours * 3600)) / 60)
        platformsContent = append(platformsContent, fmt.Sprintf("%s - Percent: %.2f - Points: %.2f - Time: %.0f hours %.0f minutes", platform.Name, platform.PercentWork, platform.Points, hours, minutes))
      }

      parWorkspace := ui.NewPar(strings.Join(platformsContent, "\n"))
      parWorkspace.Height = len(statistic.Platforms) + 2
      parWorkspace.Width = 50
      parWorkspace.TextFgColor = ui.ColorWhite
      parWorkspace.Border.Label = "Workspace Info"
      parWorkspace.Border.FgColor = ui.ColorCyan

      ui.Body.AddRows(
          ui.NewRow(ui.NewCol(12, 0, parWorkspace)))

      var languages []Language

      for name, lang := range statistic.Languages {
        level, err := ParseLevel(lang.Level)
        if err != nil {
          // don't give a fuck
          continue
        }
        languages = append(languages, Language{name, lang.Points, level.Number, level.Percent})
      }

      sort.Sort(ByLevel(languages))

      for _, lang := range languages[:numberOfLanguages] {
        g := ui.NewGauge()
        g.Percent = int(lang.Percent)
        g.Width = 50
        g.Height = 3
        g.Border.Label = fmt.Sprintf("%s Level: %d - Points: %.0f", lang.Name, lang.Level, lang.Points)
        g.BarColor = ui.ColorRed
        g.Border.FgColor = ui.ColorWhite
        g.Border.LabelFgColor = ui.ColorCyan

        ui.Body.AddRows(
          ui.NewRow(ui.NewCol(12, 0, g)))
      }

      ui.Render(ui.Body)
      ui.Body.Align()

      redraw <- true
      time.Sleep(time.Second * 10)
    }
  }

  evt := ui.EventCh()

  ui.Render(ui.Body)
  go update()

  for {
    select {
      case e := <-evt:
        if e.Type == ui.EventKey && (e.Ch == 'q' || e.Ch == 'Q' /* HEHEHEHE */) {
          log.Print("Everything went better than expected")
          return
        }
        if e.Type == ui.EventResize {
          ui.Body.Width = ui.TermWidth()
          ui.Body.Align()
          go func() { redraw <- true }()
        }
      case <-done:
        log.Print("Everything went better than expected")
        return
      case e := <-error:
        log.Fatal(e)
        return
      case <-redraw:
        ui.Body.Align()
        ui.Render(ui.Body)
    }
  }
}<commit_msg>ignore last commit, `cmd`'s history sucks<commit_after>// Number One rule: it's compiling it's working, no tests needed
// Copyright AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
// AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
// AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
// AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

// +build ignore

package main

import (
  ui "github.com/gizak/termui"
  "time"
  "strconv"
  "net/http"
  "io/ioutil"
  "encoding/json"
  "strings"
  "sort"
  "fmt"
  "math"
  "flag"
  "log"
  "errors"
)

type LangStatistic struct {
  Level string `json:"level"`
  Points float64 `json:"points"`
}

type Language struct {
  Name string
  Points float64
  Level int
  Percent float64
}

type PlatformStatistic struct {
  PercentWork float64 `json:"percent_work"`
  Points float64 `json:"points"`
  Time float64 `json:"time"`
}

type Platform struct {
  Name string
  PercentWork float64
  Points float64
  Time float64
}

type UserStatistic struct {
  CurrentLanguage string `json:"current_language"`
  FocusLevel string `json:"focus_level"`
  FocusPoints float64 `json:"focus_points"`
  Level string `json:"level"`
  MaxStreak float64 `json:"max_streak"`
  Name string `json:"name"`
  ProgrammingNow bool `json:"programming_now"`
  StreakingNow bool `json:"streaking_now"`
  TimeSpent float64 `json:"time_spent"`
  TotalDaysCoded float64 `json:"total_days_coded"`
  TotalFlowStates float64 `json:"total_flow_states"`
  Platforms map[string]PlatformStatistic `json:"platforms"`
  Languages map[string]LangStatistic `json:"languages"`
}

type ByLevel []Language
func (v ByLevel) Len() int { return len(v) }
func (v ByLevel) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
func (v ByLevel) Less(i, j int) bool {
  if v[i].Level == v[j].Level {
    if v[i].Points == v[j].Points {
      return v[i].Name > v[j].Name
    } else {
      return v[i].Points > v[j].Points
    }

  } else {
    return v[i].Level > v[j].Level
  }
}

type PlatformByPoints []Platform
func (v PlatformByPoints) Len() int { return len(v) }
func (v PlatformByPoints) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
func (v PlatformByPoints) Less(i, j int) bool {
  if v[i].Points == v[j].Points {
    if v[i].Time == v[j].Time {
      return v[i].Name > v[j].Name
    } else {
      return v[i].Time > v[j].Time
    }
  } else {
    return v[i].Points > v[j].Points
  }
}

type Level struct {
  Number int
  Percent float64
}

func ParseLevel(strLevel string) (Level, error) {
  splited := strings.Split(strLevel, ".")
  level, err := strconv.Atoi(splited[0])
  if err != nil {
    return Level{}, err
  }
  percent, err := strconv.ParseFloat(splited[1], 64)
  if err != nil {
    return Level{}, err
  }
  return Level{level, percent}, nil
}

func HandleMeLikeOneOfYourFrenchGirls(err error) {
  parUser := ui.NewPar(err.Error())
  parUser.Height = 3
  parUser.Width = 50
  parUser.TextFgColor = ui.ColorWhite
  parUser.Border.Label = "Erro acontece nada ocorre feijoada"
  parUser.Border.FgColor = ui.ColorCyan

  ui.Body.AddRows(
      ui.NewRow(ui.NewCol(12, 0, parUser)))
}

func main() {
  // yeah, if there's no username you'll see my profile :3
  var username string
  var numberOfLanguages int
  flag.StringVar(&username, "username", "schleumer", "your codeivate username")
  flag.IntVar(&numberOfLanguages, "len", 10, "number of languages to display")
  flag.Parse()

  err := ui.Init()
  if err != nil {
    panic(err)
  }
  defer ui.Close()

  ui.UseTheme("helloworld")

  done := make(chan bool)
  redraw := make(chan bool)
  error := make(chan string)

  ui.Body.Align()

  update := func () {
    for {
      // restart body
      ui.Body = ui.NewGrid()
      ui.Body.Width = ui.TermWidth()

      client := &http.Client{}
      req, err := http.NewRequest("GET", fmt.Sprintf("http://codeivate.com/users/%s.json", username), nil)
      req.Close = true
      req.Header.Set("Content-Type", "application/json")
      req.Header.Set("User-Agent", "NOTICE ME SENPAI v0.1a")

      resp, err := client.Do(req)

      if err != nil {
        HandleMeLikeOneOfYourFrenchGirls(err)
        redraw <- true
        time.Sleep(time.Second * 5)
        continue
      }

      body, err := ioutil.ReadAll(resp.Body)
      if err != nil {
        HandleMeLikeOneOfYourFrenchGirls(err)
        redraw <- true
        time.Sleep(time.Second * 5)
        continue
      }

      var statistic UserStatistic
      err = json.Unmarshal(body, &statistic)
      if err != nil {
        HandleMeLikeOneOfYourFrenchGirls(errors.New(fmt.Sprintf("Error on unmarshaling, probably the user %s doesn't exists", username)))
        redraw <- true
        time.Sleep(time.Second * 60)
        continue
      }

      userLevel, err := ParseLevel(statistic.Level)
      if err != nil {
        HandleMeLikeOneOfYourFrenchGirls(err)
        redraw <- true
        time.Sleep(time.Second * 5)
        continue
      }

      // i have no idea what i'm doing, but it's fucking hardcore
      hours := math.Floor(statistic.TimeSpent / 3600)
      minutes := math.Floor((statistic.TimeSpent - (hours * 3600)) / 60)

      parUser := ui.NewPar(fmt.Sprintf("Level: %d - Percent: %.0f - Time: %.0f hours %.0f minutes - Current Language: %s", userLevel.Number, userLevel.Percent, hours, minutes, statistic.CurrentLanguage))
      parUser.Height = 3
      parUser.Width = 50
      parUser.TextFgColor = ui.ColorWhite
      parUser.Border.Label = "User Info"
      parUser.Border.FgColor = ui.ColorCyan

      ui.Body.AddRows(
          ui.NewRow(ui.NewCol(12, 0, parUser)))

      var platformsContent []string

      var platforms []Platform

      for name, platform := range statistic.Platforms {
        platforms = append(platforms, Platform{name, platform.PercentWork, platform.Points, platform.Time})
      }

      sort.Sort(PlatformByPoints(platforms))

      for _, platform := range platforms {
        hours := math.Floor(platform.Time / 3600)
        minutes := math.Floor((platform.Time - (hours * 3600)) / 60)
        platformsContent = append(platformsContent, fmt.Sprintf("%s - Percent: %.2f - Points: %.2f - Time: %.0f hours %.0f minutes", platform.Name, platform.PercentWork, platform.Points, hours, minutes))
      }

      parWorkspace := ui.NewPar(strings.Join(platformsContent, "\n"))
      parWorkspace.Height = len(statistic.Platforms) + 2
      parWorkspace.Width = 50
      parWorkspace.TextFgColor = ui.ColorWhite
      parWorkspace.Border.Label = "Workspace Info"
      parWorkspace.Border.FgColor = ui.ColorCyan

      ui.Body.AddRows(
          ui.NewRow(ui.NewCol(12, 0, parWorkspace)))

      var languages []Language

      for name, lang := range statistic.Languages {
        level, err := ParseLevel(lang.Level)
        if err != nil {
          // don't give a fuck
          continue
        }
        languages = append(languages, Language{name, lang.Points, level.Number, level.Percent})
      }

      sort.Sort(ByLevel(languages))

      for _, lang := range languages[:numberOfLanguages] {
        g := ui.NewGauge()
        g.Percent = int(lang.Percent)
        g.Width = 50
        g.Height = 3
        g.Border.Label = fmt.Sprintf("%s Level: %d - Points: %.0f", lang.Name, lang.Level, lang.Points)
        g.BarColor = ui.ColorRed
        g.Border.FgColor = ui.ColorWhite
        g.Border.LabelFgColor = ui.ColorCyan

        ui.Body.AddRows(
          ui.NewRow(ui.NewCol(12, 0, g)))
      }

      ui.Render(ui.Body)
      ui.Body.Align()

      redraw <- true
      time.Sleep(time.Second * 10)
    }
  }

  evt := ui.EventCh()

  ui.Render(ui.Body)
  go update()

  for {
    select {
      case e := <-evt:
        if e.Type == ui.EventKey && (e.Ch == 'q' || e.Ch == 'Q' /* HEHEHEHE */) {
          log.Print("Everything went better than expected")
          return
        }
        if e.Type == ui.EventResize {
          ui.Body.Width = ui.TermWidth()
          ui.Body.Align()
          go func() { redraw <- true }()
        }
      case <-done:
        log.Print("Everything went better than expected")
        return
      case e := <-error:
        log.Fatal(e)
        return
      case <-redraw:
        ui.Body.Align()
        ui.Render(ui.Body)
    }
  }
}<|endoftext|>