<commit_before>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"strings"

	"github.com/spf13/cobra"
)

// go run *.go archive --artifact=main.go --group=com.ubanita --version=1.0-SNAPSHOT
// go run *.go fetch --artifact=main.go --group=com.ubanita --version=1.0-SNAPSHOT hier
// go run *.go list --group=com.ubanita --artifact=lucifer --version=1.0-SNAPSHOT

var VERSION string = "dev"
var BUILDDATE string = "now"

func main() {
	log.Println("_/^\\_")
	log.Println(" | | typhoon - artifact assembly tool [commit=", VERSION, "build=", BUILDDATE, "]")
	log.Println("-\\_/-")
	RootCmd.AddCommand(newArchiveCmd())
	RootCmd.AddCommand(newFetchCmd())
	RootCmd.AddCommand(newListCmd())
	RootCmd.Execute()
}

var RootCmd = &cobra.Command{
	Use:   "typhoon",
	Short: "typhoon a is a tool for artifact management",
	Run:   func(cmd *cobra.Command, args []string) {},
}

type artifactCmd struct {
	*cobra.Command
	artifact string
	group    string
	version  string
}

func newListCmd() *cobra.Command {
	cmd := newArtifactCmd(&cobra.Command{
		Use:   "list",
		Short: "list all available artifacts from the typhoon repository",
	})
	cmd.Command.Run = cmd.doList
	return cmd.Command
}

func (c *artifactCmd) doList(cmd *cobra.Command, args []string) {
	g := path.Join(strings.Split(c.group, ".")...)
	group := path.Join(getRepo(), g, c.artifact, c.version)
	files, _ := ioutil.ReadDir(group)
	for _, f := range files {
		fmt.Println(f.Name())
	}
}

type archiveCmd struct {
	*artifactCmd
	overwrite bool
}

func newArtifactCmd(cobraCmd *cobra.Command) *artifactCmd {
	cmd := new(artifactCmd)
	cmd.Command = cobraCmd
	cmd.PersistentFlags().StringVar(&cmd.artifact, "artifact", ".", "file location of artifact to copy")
	cmd.PersistentFlags().StringVar(&cmd.group, "group", ".", "folder containing the artifacts")
	cmd.PersistentFlags().StringVar(&cmd.version, "version", ".", "version of the artifact")
	return cmd
}

func newArchiveCmd() *cobra.Command {
	cmd := newArtifactCmd(&cobra.Command{
		Use:   "archive [artifact]",
		Short: "copy an artifact to the typhoon repository",
	})
	archiveCmd := new(archiveCmd)
	archiveCmd.artifactCmd = cmd
	archiveCmd.PersistentFlags().BoolVar(&archiveCmd.overwrite, "force", false, "force overwrite if version exists")
	cmd.Command.Run = archiveCmd.doArchive
	return cmd.Command
}

func getRepo() string {
	repo := os.Getenv("TYPHOON_REPO")
	if len(repo) == 0 {
		log.Fatal("missing TYPHOON_REPO environment setting")
	}
	return repo
}

func (a *archiveCmd) doArchive(cmd *cobra.Command, args []string) {
	if len(args) == 0 {
		log.Fatalf("missing artifact")
	}
	a.artifact = args[len(args)-1]
	g := path.Join(strings.Split(a.group, ".")...)
	regular := path.Base(path.Clean(a.artifact))
	p := path.Join(getRepo(), g, regular, a.version)

	log.Printf("copying %s into folder %s\n", regular, p)
	if err := os.MkdirAll(p, os.ModePerm); err != nil {
		log.Fatalf("unable to create dirs: %s cause: %v", p, err)
	}
	dest := path.Join(p, regular)

	// SNAPSHOT can be overwritten
	if strings.HasSuffix(a.version, "SNAPSHOT") {
		log.Println("will overwrite|create SNAPSHOT version")
		a.overwrite = true
	}
	if !a.overwrite && Exists(dest) {
		log.Fatalf("unable to copy artifact: %s to: %s cause: it already exists and --force=false", regular, p)
	}
	if err := Cp(dest, a.artifact); err != nil {
		log.Fatalf("unable to copy artifact: %s to: %s cause:%v", regular, p, err)
	}
}

type fetchCmd struct {
	*artifactCmd
}

func newFetchCmd() *cobra.Command {
	cmd := newArtifactCmd(&cobra.Command{
		Use:   "fetch [destination]",
		Short: "copy an artifact from the typhoon repository to [destination]",
	})
	fetch := new(fetchCmd)
	fetch.artifactCmd = cmd
	cmd.Command.Run = fetch.doFetch
	return cmd.Command
}

func (f *fetchCmd) doFetch(cmd *cobra.Command, args []string) {
	g := path.Join(strings.Split(f.group, ".")...)
	src := path.Join(getRepo(), g, f.artifact, f.version, f.artifact)
	if len(args) == 0 {
		log.Fatalf("missing destination")
	}
	if !Exists(src) {
		log.Fatalf("unable to copy artifact: %s because: no such artifact", src)
	}
	destination := args[len(args)-1]
	log.Printf("copying %s to %s\n", src, destination)
	if err := Cp(destination, src); err != nil {
		log.Fatalf("unable to copy artifact: %s to: %s because:%v", src, destination, err)
	}
}

func Exists(dest string) bool {
	_, err := os.Stat(dest)
	return err == nil
}

func Cp(dst, src string) error {
	return exec.Command("cp", src, dst).Run()
}

// Copy does what is says. Ignores errors on Close though.
func Copy(dst, src string) error {
	in, err := os.Open(src)
	if err != nil {
		return err
	}
	defer in.Close()
	out, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer out.Close()
	_, err = io.Copy(out, in)
	cerr := out.Close()
	if err != nil {
		return err
	}
	return cerr
}
<commit_msg>add version<commit_after>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"strings"

	"github.com/spf13/cobra"
)

// go run *.go archive --artifact=main.go --group=com.ubanita --version=1.0-SNAPSHOT
// go run *.go fetch --artifact=main.go --group=com.ubanita --version=1.0-SNAPSHOT hier
// go run *.go list --group=com.ubanita --artifact=lucifer --version=1.0-SNAPSHOT

var VERSION string = "dev"
var BUILDDATE string = "now"

func main() {
	RootCmd.AddCommand(newArchiveCmd())
	RootCmd.AddCommand(newFetchCmd())
	RootCmd.AddCommand(newListCmd())
	RootCmd.AddCommand(newVersionCmd())
	RootCmd.Execute()
}

var RootCmd = &cobra.Command{
	Use:   "typhoon",
	Short: "typhoon a is a tool for artifact management",
	Run:   func(cmd *cobra.Command, args []string) {},
}

func newVersionCmd() *cobra.Command {
	return &cobra.Command{
		Use:   "version",
		Short: "show build info",
		Run:   func(cmd *cobra.Command, args []string) {
			log.Println("_/^\\_")
			log.Println(" | | typhoon - artifact assembly tool [commit=", VERSION, "build=", BUILDDATE, "]")
			log.Println("-\\_/-")
		},
	})
}

type artifactCmd struct {
	*cobra.Command
	artifact string
	group    string
	version  string
}

func newListCmd() *cobra.Command {
	cmd := newArtifactCmd(&cobra.Command{
		Use:   "list",
		Short: "list all available artifacts from the typhoon repository",
	})
	cmd.Command.Run = cmd.doList
	return cmd.Command
}

func (c *artifactCmd) doList(cmd *cobra.Command, args []string) {
	g := path.Join(strings.Split(c.group, ".")...)
	group := path.Join(getRepo(), g, c.artifact, c.version)
	files, _ := ioutil.ReadDir(group)
	for _, f := range files {
		fmt.Println(f.Name())
	}
}

type archiveCmd struct {
	*artifactCmd
	overwrite bool
}

func newArtifactCmd(cobraCmd *cobra.Command) *artifactCmd {
	cmd := new(artifactCmd)
	cmd.Command = cobraCmd
	cmd.PersistentFlags().StringVar(&cmd.artifact, "artifact", ".", "file location of artifact to copy")
	cmd.PersistentFlags().StringVar(&cmd.group, "group", ".", "folder containing the artifacts")
	cmd.PersistentFlags().StringVar(&cmd.version, "version", ".", "version of the artifact")
	return cmd
}

func newArchiveCmd() *cobra.Command {
	cmd := newArtifactCmd(&cobra.Command{
		Use:   "archive [artifact]",
		Short: "copy an artifact to the typhoon repository",
	})
	archiveCmd := new(archiveCmd)
	archiveCmd.artifactCmd = cmd
	archiveCmd.PersistentFlags().BoolVar(&archiveCmd.overwrite, "force", false, "force overwrite if version exists")
	cmd.Command.Run = archiveCmd.doArchive
	return cmd.Command
}

func getRepo() string {
	repo := os.Getenv("TYPHOON_REPO")
	if len(repo) == 0 {
		log.Fatal("missing TYPHOON_REPO environment setting")
	}
	return repo
}

func (a *archiveCmd) doArchive(cmd *cobra.Command, args []string) {
	if len(args) == 0 {
		log.Fatalf("missing artifact")
	}
	a.artifact = args[len(args)-1]
	g := path.Join(strings.Split(a.group, ".")...)
	regular := path.Base(path.Clean(a.artifact))
	p := path.Join(getRepo(), g, regular, a.version)

	log.Printf("copying %s into folder %s\n", regular, p)
	if err := os.MkdirAll(p, os.ModePerm); err != nil {
		log.Fatalf("unable to create dirs: %s cause: %v", p, err)
	}
	dest := path.Join(p, regular)

	// SNAPSHOT can be overwritten
	if strings.HasSuffix(a.version, "SNAPSHOT") {
		log.Println("will overwrite|create SNAPSHOT version")
		a.overwrite = true
	}
	if !a.overwrite && Exists(dest) {
		log.Fatalf("unable to copy artifact: %s to: %s cause: it already exists and --force=false", regular, p)
	}
	if err := Cp(dest, a.artifact); err != nil {
		log.Fatalf("unable to copy artifact: %s to: %s cause:%v", regular, p, err)
	}
}

type fetchCmd struct {
	*artifactCmd
}

func newFetchCmd() *cobra.Command {
	cmd := newArtifactCmd(&cobra.Command{
		Use:   "fetch [destination]",
		Short: "copy an artifact from the typhoon repository to [destination]",
	})
	fetch := new(fetchCmd)
	fetch.artifactCmd = cmd
	cmd.Command.Run = fetch.doFetch
	return cmd.Command
}

func (f *fetchCmd) doFetch(cmd *cobra.Command, args []string) {
	g := path.Join(strings.Split(f.group, ".")...)
	src := path.Join(getRepo(), g, f.artifact, f.version, f.artifact)
	if len(args) == 0 {
		log.Fatalf("missing destination")
	}
	if !Exists(src) {
		log.Fatalf("unable to copy artifact: %s because: no such artifact", src)
	}
	destination := args[len(args)-1]
	log.Printf("copying %s to %s\n", src, destination)
	if err := Cp(destination, src); err != nil {
		log.Fatalf("unable to copy artifact: %s to: %s because:%v", src, destination, err)
	}
}

func Exists(dest string) bool {
	_, err := os.Stat(dest)
	return err == nil
}

func Cp(dst, src string) error {
	return exec.Command("cp", src, dst).Run()
}

// Copy does what is says. Ignores errors on Close though.
func Copy(dst, src string) error {
	in, err := os.Open(src)
	if err != nil {
		return err
	}
	defer in.Close()
	out, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer out.Close()
	_, err = io.Copy(out, in)
	cerr := out.Close()
	if err != nil {
		return err
	}
	return cerr
}
<|endoftext|>


<commit_before>// Package main defines a command line interface for the sqlboiler package
package main

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/kat-co/vala"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

const sqlBoilerVersion = "2.1.0"

var (
	cmdState  *State
	cmdConfig *Config
)

func main() {
	var err error

	// Too much happens between here and cobra's argument handling, for
	// something so simple just do it immediately.
	for _, arg := range os.Args {
		if arg == "--version" {
			fmt.Println("SQLBoiler v" + sqlBoilerVersion)
			return
		}
	}

	viper.SetConfigName("sqlboiler")

	configHome := os.Getenv("XDG_CONFIG_HOME")
	homePath := os.Getenv("HOME")
	wd, err := os.Getwd()
	if err != nil {
		wd = "./"
	}

	configPaths := []string{wd}
	if len(configHome) > 0 {
		configPaths = append(configPaths, filepath.Join(configHome, "sqlboiler"))
	} else {
		configPaths = append(configPaths, filepath.Join(homePath, ".config/sqlboiler"))
	}

	for _, p := range configPaths {
		viper.AddConfigPath(p)
	}

	// Ignore errors here, fallback to other validation methods.
	// Users can use environment variables if a config is not found.
	_ = viper.ReadInConfig()

	// Set up the cobra root command
	var rootCmd = &cobra.Command{
		Use:   "sqlboiler [flags] <driver>",
		Short: "SQL Boiler generates an ORM tailored to your database schema.",
		Long: "SQL Boiler generates a Go ORM from template files, tailored to your database schema.\n" +
			`Complete documentation is available at http://github.com/vattle/sqlboiler`,
		Example:       `sqlboiler postgres`,
		PreRunE:       preRun,
		RunE:          run,
		PostRunE:      postRun,
		SilenceErrors: true,
		SilenceUsage:  true,
	}

	// Set up the cobra root command flags
	rootCmd.PersistentFlags().StringP("output", "o", "models", "The name of the folder to output to")
	rootCmd.PersistentFlags().StringP("schema", "s", "public", "The name of your database schema, for databases that support real schemas")
	rootCmd.PersistentFlags().StringP("pkgname", "p", "models", "The name you wish to assign to your generated package")
	rootCmd.PersistentFlags().StringP("basedir", "", "", "The base directory has the templates and templates_test folders")
	rootCmd.PersistentFlags().StringSliceP("blacklist", "b", nil, "Do not include these tables in your generated package")
	rootCmd.PersistentFlags().StringSliceP("whitelist", "w", nil, "Only include these tables in your generated package")
	rootCmd.PersistentFlags().StringSliceP("tag", "t", nil, "Struct tags to be included on your models in addition to json, yaml, toml")
	rootCmd.PersistentFlags().BoolP("debug", "d", false, "Debug mode prints stack traces on error")
	rootCmd.PersistentFlags().BoolP("no-tests", "", false, "Disable generated go test files")
	rootCmd.PersistentFlags().BoolP("no-hooks", "", false, "Disable hooks feature for your models")
	rootCmd.PersistentFlags().BoolP("no-auto-timestamps", "", false, "Disable automatic timestamps for created_at/updated_at")
	rootCmd.PersistentFlags().BoolP("version", "", false, "Print the version")

	viper.SetDefault("postgres.sslmode", "require")
	viper.SetDefault("postgres.port", "5432")
	viper.SetDefault("mysql.sslmode", "true")
	viper.SetDefault("mysql.port", "3306")

	viper.BindPFlags(rootCmd.PersistentFlags())
	viper.AutomaticEnv()

	if err := rootCmd.Execute(); err != nil {
		if e, ok := err.(commandFailure); ok {
			fmt.Printf("Error: %v\n\n", string(e))
			rootCmd.Help()
		} else if !viper.GetBool("debug") {
			fmt.Printf("Error: %v\n", err)
		} else {
			fmt.Printf("Error: %+v\n", err)
		}

		os.Exit(1)
	}
}

type commandFailure string

func (c commandFailure) Error() string {
	return string(c)
}

func preRun(cmd *cobra.Command, args []string) error {
	var err error

	if len(args) == 0 {
		return commandFailure("must provide a driver name")
	}

	driverName := args[0]

	cmdConfig = &Config{
		DriverName:       driverName,
		OutFolder:        viper.GetString("output"),
		Schema:           viper.GetString("schema"),
		PkgName:          viper.GetString("pkgname"),
		BaseDir:          viper.GetString("basedir"),
		Debug:            viper.GetBool("debug"),
		NoTests:          viper.GetBool("no-tests"),
		NoHooks:          viper.GetBool("no-hooks"),
		NoAutoTimestamps: viper.GetBool("no-auto-timestamps"),
	}

	// BUG: https://github.com/spf13/viper/issues/200
	// Look up the value of blacklist, whitelist & tags directly from PFlags in Cobra if we
	// detect a malformed value coming out of viper.
	// Once the bug is fixed we'll be able to move this into the init above
	cmdConfig.BlacklistTables = viper.GetStringSlice("blacklist")
	if len(cmdConfig.BlacklistTables) == 1 && strings.HasPrefix(cmdConfig.BlacklistTables[0], "[") {
		cmdConfig.BlacklistTables, err = cmd.PersistentFlags().GetStringSlice("blacklist")
		if err != nil {
			return err
		}
	}

	cmdConfig.WhitelistTables = viper.GetStringSlice("whitelist")
	if len(cmdConfig.WhitelistTables) == 1 && strings.HasPrefix(cmdConfig.WhitelistTables[0], "[") {
		cmdConfig.WhitelistTables, err = cmd.PersistentFlags().GetStringSlice("whitelist")
		if err != nil {
			return err
		}
	}

	cmdConfig.Tags = viper.GetStringSlice("tag")
	if len(cmdConfig.Tags) == 1 && strings.HasPrefix(cmdConfig.Tags[0], "[") {
		cmdConfig.Tags, err = cmd.PersistentFlags().GetStringSlice("tag")
		if err != nil {
			return err
		}
	}

	if driverName == "postgres" {
		cmdConfig.Postgres = PostgresConfig{
			User:    viper.GetString("postgres.user"),
			Pass:    viper.GetString("postgres.pass"),
			Host:    viper.GetString("postgres.host"),
			Port:    viper.GetInt("postgres.port"),
			DBName:  viper.GetString("postgres.dbname"),
			SSLMode: viper.GetString("postgres.sslmode"),
		}

		// BUG: https://github.com/spf13/viper/issues/71
		// Despite setting defaults, nested values don't get defaults
		// Set them manually
		if cmdConfig.Postgres.SSLMode == "" {
			cmdConfig.Postgres.SSLMode = "require"
			viper.Set("postgres.sslmode", cmdConfig.Postgres.SSLMode)
		}

		if cmdConfig.Postgres.Port == 0 {
			cmdConfig.Postgres.Port = 5432
			viper.Set("postgres.port", cmdConfig.Postgres.Port)
		}

		err = vala.BeginValidation().Validate(
			vala.StringNotEmpty(cmdConfig.Postgres.User, "postgres.user"),
			vala.StringNotEmpty(cmdConfig.Postgres.Host, "postgres.host"),
			vala.Not(vala.Equals(cmdConfig.Postgres.Port, 0, "postgres.port")),
			vala.StringNotEmpty(cmdConfig.Postgres.DBName, "postgres.dbname"),
			vala.StringNotEmpty(cmdConfig.Postgres.SSLMode, "postgres.sslmode"),
		).Check()

		if err != nil {
			return commandFailure(err.Error())
		}
	}

	if driverName == "mysql" {
		cmdConfig.MySQL = MySQLConfig{
			User:    viper.GetString("mysql.user"),
			Pass:    viper.GetString("mysql.pass"),
			Host:    viper.GetString("mysql.host"),
			Port:    viper.GetInt("mysql.port"),
			DBName:  viper.GetString("mysql.dbname"),
			SSLMode: viper.GetString("mysql.sslmode"),
		}

		// MySQL doesn't have schemas, just databases
		cmdConfig.Schema = cmdConfig.MySQL.DBName

		// BUG: https://github.com/spf13/viper/issues/71
		// Despite setting defaults, nested values don't get defaults
		// Set them manually
		if cmdConfig.MySQL.SSLMode == "" {
			cmdConfig.MySQL.SSLMode = "true"
			viper.Set("mysql.sslmode", cmdConfig.MySQL.SSLMode)
		}

		if cmdConfig.MySQL.Port == 0 {
			cmdConfig.MySQL.Port = 3306
			viper.Set("mysql.port", cmdConfig.MySQL.Port)
		}

		err = vala.BeginValidation().Validate(
			vala.StringNotEmpty(cmdConfig.MySQL.User, "mysql.user"),
			vala.StringNotEmpty(cmdConfig.MySQL.Host, "mysql.host"),
			vala.Not(vala.Equals(cmdConfig.MySQL.Port, 0, "mysql.port")),
			vala.StringNotEmpty(cmdConfig.MySQL.DBName, "mysql.dbname"),
			vala.StringNotEmpty(cmdConfig.MySQL.SSLMode, "mysql.sslmode"),
		).Check()

		if err != nil {
			return commandFailure(err.Error())
		}
	}

	cmdState, err = New(cmdConfig)
	return err
}

func run(cmd *cobra.Command, args []string) error {
	return cmdState.Run(true)
}

func postRun(cmd *cobra.Command, args []string) error {
	return cmdState.Cleanup()
}
<commit_msg>Bump 2.1.1<commit_after>// Package main defines a command line interface for the sqlboiler package
package main

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/kat-co/vala"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

const sqlBoilerVersion = "2.1.1"

var (
	cmdState  *State
	cmdConfig *Config
)

func main() {
	var err error

	// Too much happens between here and cobra's argument handling, for
	// something so simple just do it immediately.
	for _, arg := range os.Args {
		if arg == "--version" {
			fmt.Println("SQLBoiler v" + sqlBoilerVersion)
			return
		}
	}

	viper.SetConfigName("sqlboiler")

	configHome := os.Getenv("XDG_CONFIG_HOME")
	homePath := os.Getenv("HOME")
	wd, err := os.Getwd()
	if err != nil {
		wd = "./"
	}

	configPaths := []string{wd}
	if len(configHome) > 0 {
		configPaths = append(configPaths, filepath.Join(configHome, "sqlboiler"))
	} else {
		configPaths = append(configPaths, filepath.Join(homePath, ".config/sqlboiler"))
	}

	for _, p := range configPaths {
		viper.AddConfigPath(p)
	}

	// Ignore errors here, fallback to other validation methods.
	// Users can use environment variables if a config is not found.
	_ = viper.ReadInConfig()

	// Set up the cobra root command
	var rootCmd = &cobra.Command{
		Use:   "sqlboiler [flags] <driver>",
		Short: "SQL Boiler generates an ORM tailored to your database schema.",
		Long: "SQL Boiler generates a Go ORM from template files, tailored to your database schema.\n" +
			`Complete documentation is available at http://github.com/vattle/sqlboiler`,
		Example:       `sqlboiler postgres`,
		PreRunE:       preRun,
		RunE:          run,
		PostRunE:      postRun,
		SilenceErrors: true,
		SilenceUsage:  true,
	}

	// Set up the cobra root command flags
	rootCmd.PersistentFlags().StringP("output", "o", "models", "The name of the folder to output to")
	rootCmd.PersistentFlags().StringP("schema", "s", "public", "The name of your database schema, for databases that support real schemas")
	rootCmd.PersistentFlags().StringP("pkgname", "p", "models", "The name you wish to assign to your generated package")
	rootCmd.PersistentFlags().StringP("basedir", "", "", "The base directory has the templates and templates_test folders")
	rootCmd.PersistentFlags().StringSliceP("blacklist", "b", nil, "Do not include these tables in your generated package")
	rootCmd.PersistentFlags().StringSliceP("whitelist", "w", nil, "Only include these tables in your generated package")
	rootCmd.PersistentFlags().StringSliceP("tag", "t", nil, "Struct tags to be included on your models in addition to json, yaml, toml")
	rootCmd.PersistentFlags().BoolP("debug", "d", false, "Debug mode prints stack traces on error")
	rootCmd.PersistentFlags().BoolP("no-tests", "", false, "Disable generated go test files")
	rootCmd.PersistentFlags().BoolP("no-hooks", "", false, "Disable hooks feature for your models")
	rootCmd.PersistentFlags().BoolP("no-auto-timestamps", "", false, "Disable automatic timestamps for created_at/updated_at")
	rootCmd.PersistentFlags().BoolP("version", "", false, "Print the version")

	viper.SetDefault("postgres.sslmode", "require")
	viper.SetDefault("postgres.port", "5432")
	viper.SetDefault("mysql.sslmode", "true")
	viper.SetDefault("mysql.port", "3306")

	viper.BindPFlags(rootCmd.PersistentFlags())
	viper.AutomaticEnv()

	if err := rootCmd.Execute(); err != nil {
		if e, ok := err.(commandFailure); ok {
			fmt.Printf("Error: %v\n\n", string(e))
			rootCmd.Help()
		} else if !viper.GetBool("debug") {
			fmt.Printf("Error: %v\n", err)
		} else {
			fmt.Printf("Error: %+v\n", err)
		}

		os.Exit(1)
	}
}

type commandFailure string

func (c commandFailure) Error() string {
	return string(c)
}

func preRun(cmd *cobra.Command, args []string) error {
	var err error

	if len(args) == 0 {
		return commandFailure("must provide a driver name")
	}

	driverName := args[0]

	cmdConfig = &Config{
		DriverName:       driverName,
		OutFolder:        viper.GetString("output"),
		Schema:           viper.GetString("schema"),
		PkgName:          viper.GetString("pkgname"),
		BaseDir:          viper.GetString("basedir"),
		Debug:            viper.GetBool("debug"),
		NoTests:          viper.GetBool("no-tests"),
		NoHooks:          viper.GetBool("no-hooks"),
		NoAutoTimestamps: viper.GetBool("no-auto-timestamps"),
	}

	// BUG: https://github.com/spf13/viper/issues/200
	// Look up the value of blacklist, whitelist & tags directly from PFlags in Cobra if we
	// detect a malformed value coming out of viper.
	// Once the bug is fixed we'll be able to move this into the init above
	cmdConfig.BlacklistTables = viper.GetStringSlice("blacklist")
	if len(cmdConfig.BlacklistTables) == 1 && strings.HasPrefix(cmdConfig.BlacklistTables[0], "[") {
		cmdConfig.BlacklistTables, err = cmd.PersistentFlags().GetStringSlice("blacklist")
		if err != nil {
			return err
		}
	}

	cmdConfig.WhitelistTables = viper.GetStringSlice("whitelist")
	if len(cmdConfig.WhitelistTables) == 1 && strings.HasPrefix(cmdConfig.WhitelistTables[0], "[") {
		cmdConfig.WhitelistTables, err = cmd.PersistentFlags().GetStringSlice("whitelist")
		if err != nil {
			return err
		}
	}

	cmdConfig.Tags = viper.GetStringSlice("tag")
	if len(cmdConfig.Tags) == 1 && strings.HasPrefix(cmdConfig.Tags[0], "[") {
		cmdConfig.Tags, err = cmd.PersistentFlags().GetStringSlice("tag")
		if err != nil {
			return err
		}
	}

	if driverName == "postgres" {
		cmdConfig.Postgres = PostgresConfig{
			User:    viper.GetString("postgres.user"),
			Pass:    viper.GetString("postgres.pass"),
			Host:    viper.GetString("postgres.host"),
			Port:    viper.GetInt("postgres.port"),
			DBName:  viper.GetString("postgres.dbname"),
			SSLMode: viper.GetString("postgres.sslmode"),
		}

		// BUG: https://github.com/spf13/viper/issues/71
		// Despite setting defaults, nested values don't get defaults
		// Set them manually
		if cmdConfig.Postgres.SSLMode == "" {
			cmdConfig.Postgres.SSLMode = "require"
			viper.Set("postgres.sslmode", cmdConfig.Postgres.SSLMode)
		}

		if cmdConfig.Postgres.Port == 0 {
			cmdConfig.Postgres.Port = 5432
			viper.Set("postgres.port", cmdConfig.Postgres.Port)
		}

		err = vala.BeginValidation().Validate(
			vala.StringNotEmpty(cmdConfig.Postgres.User, "postgres.user"),
			vala.StringNotEmpty(cmdConfig.Postgres.Host, "postgres.host"),
			vala.Not(vala.Equals(cmdConfig.Postgres.Port, 0, "postgres.port")),
			vala.StringNotEmpty(cmdConfig.Postgres.DBName, "postgres.dbname"),
			vala.StringNotEmpty(cmdConfig.Postgres.SSLMode, "postgres.sslmode"),
		).Check()

		if err != nil {
			return commandFailure(err.Error())
		}
	}

	if driverName == "mysql" {
		cmdConfig.MySQL = MySQLConfig{
			User:    viper.GetString("mysql.user"),
			Pass:    viper.GetString("mysql.pass"),
			Host:    viper.GetString("mysql.host"),
			Port:    viper.GetInt("mysql.port"),
			DBName:  viper.GetString("mysql.dbname"),
			SSLMode: viper.GetString("mysql.sslmode"),
		}

		// MySQL doesn't have schemas, just databases
		cmdConfig.Schema = cmdConfig.MySQL.DBName

		// BUG: https://github.com/spf13/viper/issues/71
		// Despite setting defaults, nested values don't get defaults
		// Set them manually
		if cmdConfig.MySQL.SSLMode == "" {
			cmdConfig.MySQL.SSLMode = "true"
			viper.Set("mysql.sslmode", cmdConfig.MySQL.SSLMode)
		}

		if cmdConfig.MySQL.Port == 0 {
			cmdConfig.MySQL.Port = 3306
			viper.Set("mysql.port", cmdConfig.MySQL.Port)
		}

		err = vala.BeginValidation().Validate(
			vala.StringNotEmpty(cmdConfig.MySQL.User, "mysql.user"),
			vala.StringNotEmpty(cmdConfig.MySQL.Host, "mysql.host"),
			vala.Not(vala.Equals(cmdConfig.MySQL.Port, 0, "mysql.port")),
			vala.StringNotEmpty(cmdConfig.MySQL.DBName, "mysql.dbname"),
			vala.StringNotEmpty(cmdConfig.MySQL.SSLMode, "mysql.sslmode"),
		).Check()

		if err != nil {
			return commandFailure(err.Error())
		}
	}

	cmdState, err = New(cmdConfig)
	return err
}

func run(cmd *cobra.Command, args []string) error {
	return cmdState.Run(true)
}

func postRun(cmd *cobra.Command, args []string) error {
	return cmdState.Cleanup()
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"
	"time"
)

func setConfig(nsqAddr string, lookupdIPs []net.IP) {
	body, err := json.Marshal(lookupdIPs)
	if err != nil {
		log.Fatal(err)
	}

	log.Printf("setting lookupdIPs: %s", body)

	configAddr := "http://" + nsqAddr + "/config/nsqlookupd_tcp_addresses"
	req, err := http.NewRequest("PUT", configAddr, bytes.NewBuffer(body))
	if err != nil {
		log.Fatalf("http.NewRequest error: %s", err)
	}

	client := &http.Client{}
	res, err := client.Do(req)
	if err != nil {
		log.Fatalf("client.Do error: %s", err)
	}

	if res.StatusCode != 200 {
		log.Printf("nsqd responded with status: %d", res.StatusCode)
	}
}

func main() {
	var (
		dnsAddr  = flag.String("lookupd-dns-address", "", "The DNS address of nsqlookupd")
		nsqdAddr = flag.String("nsqd-http-address", "0.0.0.0:4151", "The HTTP address of nsqd")
	)
	flag.Parse()

	if *dnsAddr == "" {
		fmt.Println("Error: required arg -lookupd-dns-address")
		return
	}

	lookupdIPs, err := net.LookupIP(*dnsAddr)
	if err != nil {
		log.Fatalf("net.LookupIP error: %s", err)
	}

	if len(lookupdIPs) == 0 {
		log.Fatalf("no IPs found for %s", *dnsAddr)
	}

	setConfig(*nsqdAddr, lookupdIPs)
	ticker := time.Tick(15 * time.Second)

	for {
		select {
		case <-ticker:
			lookupdIPs, err := net.LookupIP(*dnsAddr)
			if err != nil {
				log.Fatal(err)
			}

			if len(lookupdIPs) == 0 {
				log.Printf("No IP addresses found for %s", *dnsAddr)
				continue
			}

			setConfig(*nsqdAddr, lookupdIPs)
		}
	}
}
<commit_msg>Add nsqlookupd tcp port as option<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"
	"time"
)

func setConfig(nsqAddr string, lookupdPort int, lookupdIPs []net.IP) {
	lookupdTCPAddrs := []string{}
	for _, IP := range lookupdIPs {
		addr := fmt.Sprintf("%s:%d", IP, lookupdPort)
		lookupdTCPAddrs = append(lookupdTCPAddrs, addr)
	}

	body, err := json.Marshal(lookupdTCPAddrs)
	if err != nil {
		log.Fatal(err)
	}

	log.Printf("setting lookupdTCPAddrs: %s", body)

	configAddr := "http://" + nsqAddr + "/config/nsqlookupd_tcp_addresses"
	req, err := http.NewRequest("PUT", configAddr, bytes.NewBuffer(body))
	if err != nil {
		log.Fatalf("http.NewRequest error: %s", err)
	}

	client := &http.Client{}
	res, err := client.Do(req)
	if err != nil {
		log.Fatalf("client.Do error: %s", err)
	}

	if res.StatusCode != 200 {
		log.Printf("nsqd responded with status: %d", res.StatusCode)
	}
}

func main() {
	var (
		lookupdPort = flag.Int("lookupd-tcp-port", 4160, "The nsqlookupd tcp port")
		dnsAddr  = flag.String("lookupd-dns-address", "", "The DNS address of nsqlookupd")
		nsqdAddr = flag.String("nsqd-http-address", "0.0.0.0:4151", "The HTTP address of nsqd")
	)
	flag.Parse()

	if *dnsAddr == "" {
		fmt.Println("Error: required arg -lookupd-dns-address")
		return
	}

	lookupdIPs, err := net.LookupIP(*dnsAddr)
	if err != nil {
		log.Fatalf("net.LookupIP error: %s", err)
	}

	if len(lookupdIPs) == 0 {
		log.Fatalf("no IPs found for %s", *dnsAddr)
	}

	setConfig(*nsqdAddr, *lookupdPort, lookupdIPs)
	ticker := time.Tick(15 * time.Second)

	for {
		select {
		case <-ticker:
			lookupdIPs, err := net.LookupIP(*dnsAddr)
			if err != nil {
				log.Fatal(err)
			}

			if len(lookupdIPs) == 0 {
				log.Printf("No IP addresses found for %s", *dnsAddr)
				continue
			}

			setConfig(*nsqdAddr, *lookupdPort, lookupdIPs)
		}
	}
}
<|endoftext|>


<commit_before>/*
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

// Gouplo is a simple & easy-to-use fileserver written in Go (golang.org).
package main

import (
	"crypto/md5"
	"crypto/subtle"
	"encoding/json"
	"flag"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
)

var cfgPath = flag.String("config", "config.json", "path to config file (in JSON format)")
var cfg config

func main() {
	flag.Parse()
	cfg = loadConfig(*cfgPath)
	http.HandleFunc("/", authHandler(indexHandler, hasher(cfg.User), hasher(cfg.Pass), cfg.Realm))
	http.HandleFunc("/upload", uploadHandler)
	http.Handle("/pub/", http.StripPrefix("/pub/", http.FileServer(http.Dir(cfg.PubDir))))
	go func() {
		err := http.ListenAndServeTLS(":"+cfg.HTTPSPort, cfg.CertPem, cfg.KeyPem, nil)
		if err != nil {
			log.Fatal("ListenAndServeTLS:", err)
		}
	}()
	err := http.ListenAndServe(":"+cfg.HTTPPort, http.RedirectHandler("https://"+cfg.Domain+":"+cfg.HTTPSPort, 301))
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

// hasher hashes the given string and returns the sum as a slice of bytes.
func hasher(s string) []byte {
	val := md5.Sum([]byte(s))
	return val[:]
}

// config type contains the necessary server configuration strings.
type config struct {
	HTTPPort, HTTPSPort, IndexFile, PubDir, UpDir, User, Pass, Realm,
	Domain, CertPem, KeyPem string
}

// loadConfig loads configuration values from file.
func loadConfig(path string) (c config) {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		log.Fatal(err)
	}
	err = json.Unmarshal(b, &c)
	if err != nil {
		log.Fatal(err)
	}
	return
}

func indexHandler(w http.ResponseWriter, r *http.Request) {
	template.Must(template.ParseFiles(cfg.IndexFile)).Execute(w, r.Host)
}

func uploadHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		w.WriteHeader(http.StatusMethodNotAllowed)
	} else {
		err := r.ParseMultipartForm(100000)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		m := r.MultipartForm
		files := m.File["files"]
		for i := range files {
			file, err := files[i].Open() //open file
			defer file.Close()
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			dst, err := os.Create(cfg.UpDir + "/" + files[i].Filename) //ensure destination is writeable
			defer dst.Close()
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			if _, err := io.Copy(dst, file); err != nil { //write the file to destination
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		}
		io.WriteString(w, "successful")
	}
}

// authHandler wraps a handler function to provide http basic authentication.
func authHandler(handler http.HandlerFunc, userhash, passhash []byte, realm string) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		user, pass, ok := r.BasicAuth()
		if !ok || subtle.ConstantTimeCompare(hasher(user),
			userhash) != 1 || subtle.ConstantTimeCompare(hasher(pass), passhash) != 1 {
			w.Header().Set("WWW-Authenticate", `Basic realm="`+realm+`"`)
			http.Error(w, "Unauthorized.", http.StatusUnauthorized)
			return
		}
		handler(w, r)
	}
}
<commit_msg>Upgraded md5 hashing to sha256.<commit_after>/*
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

// Gouplo is a simple & easy-to-use fileserver written in Go (golang.org).
package main

import (
	"crypto/sha256"
	"crypto/subtle"
	"encoding/json"
	"flag"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
)

var cfgPath = flag.String("config", "config.json", "path to config file (in JSON format)")
var cfg config

func main() {
	flag.Parse()
	cfg = loadConfig(*cfgPath)
	http.HandleFunc("/", authHandler(indexHandler, hasher(cfg.User), hasher(cfg.Pass), cfg.Realm))
	http.HandleFunc("/upload", uploadHandler)
	http.Handle("/pub/", http.StripPrefix("/pub/", http.FileServer(http.Dir(cfg.PubDir))))
	go func() {
		err := http.ListenAndServeTLS(":"+cfg.HTTPSPort, cfg.CertPem, cfg.KeyPem, nil)
		if err != nil {
			log.Fatal("ListenAndServeTLS:", err)
		}
	}()
	err := http.ListenAndServe(":"+cfg.HTTPPort, http.RedirectHandler("https://"+cfg.Domain+":"+cfg.HTTPSPort, 301))
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

// hasher hashes the given string and returns the sum as a slice of bytes.
func hasher(s string) []byte {
	val := sha256.Sum256([]byte(s)) // old: md5.Sum([]byte(s))
	return val[:]
}

// config type contains the necessary server configuration strings.
type config struct {
	HTTPPort, HTTPSPort, IndexFile, PubDir, UpDir, User, Pass, Realm,
	Domain, CertPem, KeyPem string
}

// loadConfig loads configuration values from file.
func loadConfig(path string) (c config) {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		log.Fatal(err)
	}
	err = json.Unmarshal(b, &c)
	if err != nil {
		log.Fatal(err)
	}
	return
}

func indexHandler(w http.ResponseWriter, r *http.Request) {
	template.Must(template.ParseFiles(cfg.IndexFile)).Execute(w, r.Host)
}

func uploadHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		w.WriteHeader(http.StatusMethodNotAllowed)
	} else {
		err := r.ParseMultipartForm(100000)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		m := r.MultipartForm
		files := m.File["files"]
		for i := range files {
			file, err := files[i].Open() //open file
			defer file.Close()
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			dst, err := os.Create(cfg.UpDir + "/" + files[i].Filename) //ensure destination is writeable
			defer dst.Close()
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			if _, err := io.Copy(dst, file); err != nil { //write the file to destination
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		}
		io.WriteString(w, "successful")
	}
}

// authHandler wraps a handler function to provide http basic authentication.
func authHandler(handler http.HandlerFunc, userhash, passhash []byte, realm string) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		user, pass, ok := r.BasicAuth()
		if !ok || subtle.ConstantTimeCompare(hasher(user),
			userhash) != 1 || subtle.ConstantTimeCompare(hasher(pass), passhash) != 1 {
			w.Header().Set("WWW-Authenticate", `Basic realm="`+realm+`"`)
			http.Error(w, "Unauthorized.", http.StatusUnauthorized)
			return
		}
		handler(w, r)
	}
}
<|endoftext|>


<commit_before>// netbackup - Consistent multi-method backup tool
//
// See instructions in the README.md file that accompanies this program.
//
// (C) 2015 by Marco Paganini <paganini AT paganini DOT net>

package main

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"time"

	"github.com/marcopaganini/logger"
	"github.com/marcopaganini/netbackup/config"
	"github.com/marcopaganini/netbackup/execute"
	"github.com/marcopaganini/netbackup/transports"
)

const (
	defaultLogDir = "/tmp/log/netbackup"
	devMapperDir  = "/dev/mapper"

	// Default permissions for log directories and files.
	// The current umask will apply to these.
	defaultLogDirMode  = 0777
	defaultLogFileMode = 0666

	// Return codes
	osSuccess = 0
	osError   = 1

	// External commands.
	mountCmd      = "mount"
	umountCmd     = "umount"
	cryptSetupCmd = "cryptsetup"
	fsckCmd       = "fsck"
	tunefsCmd     = "tune2fs"
)

var (
	// Generic logging object
	log *logger.Logger
)

// usage prints an error message and program usage to stderr, exiting after
// that.
func usage(err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %v\n\n", err)
	}
	fmt.Fprintf(os.Stderr, "Usage%s:\n", os.Args[0])
	flag.PrintDefaults()
	os.Exit(2)
}

// createOutputLog creates a new output log file. If logPath is set, it is used
// unchanged. If not, a new log is created based under logDir using the
// configuration name, and the system date. Intermediate directories are
// created as needed. Returns a *os.File, the file created, error.
func createOutputLog(logPath string, logDir string, configName string) (*os.File, string, error) {
	path := logPath
	if path == "" {
		dir := filepath.Join(logDir, configName)
		if err := os.MkdirAll(dir, defaultLogDirMode); err != nil {
			return nil, "", fmt.Errorf("Error trying to create dir tree %q: %v", dir, err)
		}
		ymd := time.Now().Format("2006-01-02")
		path = filepath.Join(dir, configName+"-"+ymd+".log")
	}

	w, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, defaultLogFileMode)
	if err != nil {
		return nil, path, fmt.Errorf("Error opening %q: %v", path, err)
	}
	return w, path, err
}

// shellRun run a command string using the shell using the specified execute object.
func shellRun(e *execute.Execute, cmd string) error {
	shell := os.Getenv("SHELL")
	if shell == "" {
		shell = "/bin/sh"
	}
	a := []string{shell, "-c", "--", cmd}
	return e.Exec(a)
}

// runCommand executes the pre or post commands using the shell. A prefix will
// be used to log the commands to the output log (usually, "PRE" for
// pre-commands or "POST" for post-commands Returns error.
func runCommand(prefix string, cmd string, ex *execute.Execute, outLog io.Writer) error {
	m := fmt.Sprintf("%s Command: %q", prefix, cmd)
	log.Verboseln(int(opt.verbose), m)
	if opt.dryrun {
		return nil
	}

	// Create a new execute object, if current is nil
	e := ex
	if e == nil {
		e = execute.New()
	}

	// All streams copied to output log with "PRE:" as a prefix.
	e.SetStdout(func(buf string) error { _, err := fmt.Fprintf(outLog, "%s(stdout): %s\n", prefix, buf); return err })
	e.SetStderr(func(buf string) error { _, err := fmt.Fprintf(outLog, "%s(stderr): %s\n", prefix, buf); return err })

	fmt.Fprintf(outLog, "*** %s\n", m)
	err := shellRun(e, cmd)
	fmt.Fprintf(outLog, "*** %s returned: %v\n", prefix, err)

	return err
}

// mountDestDev mounts the destination device specified in config.DestDev into
// a temporary mount point and set config.DestDir to point to this directory.
func mountDestDev(config *config.Config, outLog io.Writer) error {
	tmpdir, err := ioutil.TempDir("", "netbackup_mount")
	if err != nil {
		return fmt.Errorf("unable to create temp directory: %v", err)
	}

	// We use the mount command instead of the mount syscal as it makes
	// simpler to specify defaults in /etc/fstab.
	cmd := mountCmd + " " + config.DestDev + " " + tmpdir
	if err := runCommand("MOUNT", cmd, nil, outLog); err != nil {
		return fmt.Errorf("error running %q: %v", cmd, err)
	}

	config.DestDir = tmpdir
	return nil
}

// umountDestDev dismounts the destination device specified in config.DestDev.
func umountDestDev(config *config.Config, outLog io.Writer) error {
	cmd := umountCmd + " " + config.DestDev
	if err := runCommand("UMOUNT", cmd, nil, outLog); err != nil {
		return fmt.Errorf("error running %q: %v", cmd, err)
	}
	return nil
}

// openLuksDestDev opens the luks device specified by config.LuksDestDev and sets
// config.DestDev to the /dev/mapper device.
func openLuksDestDev(config *config.Config, outLog io.Writer) error {
	// Our temporary dev/mapper device is based on the config name
	devname := "netbackup_" + config.Name
	devfile := filepath.Join(devMapperDir, devname)

	// Make sure it doesn't already exist
	if _, err := os.Stat(devfile); err == nil {
		return fmt.Errorf("device mapper file %q already exists.", devfile)
	}

	// cryptsetup LuksOpen
	cmd := cryptSetupCmd
	if config.LuksKeyFile != "" {
		cmd += " --key-file " + config.LuksKeyFile
	}
	cmd += " luksOpen " + config.LuksDestDev + " " + devname
	if err := runCommand("LUKS_OPEN", cmd, nil, outLog); err != nil {
		return fmt.Errorf("error running %q: %v", cmd, err)
	}

	// Set the destination device to devfile so the normal processing
	// will be sufficient to mount and dismount this device.
	config.DestDev = devfile
	return nil
}

// closeLuksDestDev closes the luks device specified by config.LuksDestDev.
func closeLuksDestDev(config *config.Config, outLog io.Writer) error {
	// Note that even though this function is called closeLuksDestDev we use
	// the mount point under /dev/mapper to close the device.  The mount point
	// was previously set by openLuksDestDev.
	cmd := cryptSetupCmd + " luksClose " + config.DestDev
	if err := runCommand("LUKS_CLOSE", cmd, nil, outLog); err != nil {
		return fmt.Errorf("error running %q: %v", cmd, err)
	}
	return nil
}

// fsCleanup runs fsck to make sure the filesystem under config.dest_dev is
// intact, and sets the number of times to check to 0 and the last time
// checked to now. This option should only be used in EXTn filesystems or
// filesystems that support tunefs.
func fsCleanup(config *config.Config, outLog io.Writer) error {
	// fsck (read-only check)
	cmd := fsckCmd + " -n " + config.DestDev
	if err := runCommand("FS_CLEANUP", cmd, nil, outLog); err != nil {
		return fmt.Errorf("error running %q: %v", cmd, err)
	}
	// Tunefs
	cmd = tunefsCmd + " -C 0 -T now " + config.DestDev
	if err := runCommand("FS_CLEANUP", cmd, nil, outLog); err != nil {
		return fmt.Errorf("error running %q: %v", cmd, err)
	}
	return nil
}

func backup() int {
	var transp interface {
		Run() error
	}
	log = logger.New("")

	// Parse command line flags and read config file.
	if err := parseFlags(); err != nil {
		log.Printf("Error: %v", err)
		return osError
	}
	// Set verbose level
	if opt.verbose > 0 {
		log.SetVerboseLevel(int(opt.verbose))
	}
	if opt.dryrun {
		log.Verbosef(2, "Warning: Dry-Run mode. Won't execute any commands.")
	}

	// Open and parse config file
	cfg, err := os.Open(opt.config)
	if err != nil {
		log.Printf("Unable to open config file: %v", err)
		return osError
	}
	config, err := config.ParseConfig(cfg)
	if err != nil {
		log.Printf("Configuration error in %q: %v", opt.config, err)
		return osError
	}

	// Open or create the output log file. This log will contain a transcript
	// of stdout and stderr from all commands executed by this program.
	outLog, outPath, err := createOutputLog(config.Logfile, defaultLogDir, config.Name)
	if err != nil {
		log.Printf("Error opening output logfile: %q: %v", outPath, err)
		return osError
	}
	defer outLog.Close()

	if !opt.dryrun {
		// Open LUKS device, if needed
		if config.LuksDestDev != "" {
			if err := openLuksDestDev(config, outLog); err != nil {
				log.Printf("Error opening LUKS device %q: %v", config.LuksDestDev, err)
				return osError
			}
			// close luks device at the end
			defer closeLuksDestDev(config, outLog)
			defer time.Sleep(2 * time.Second)
		}

		// Run cleanup on fs prior to backup, if requested.
		if config.FSCleanup {
			if err := fsCleanup(config, outLog); err != nil {
				log.Printf("Error performing pre-backup cleanup on %q: %v", config.DestDev, err)
				return osError
			}
		}

		// Mount destination device, if needed.
		if config.DestDev != "" {
			if err := mountDestDev(config, outLog); err != nil {
				log.Printf("Error opening destination device %q: %v", config.DestDev, err)
				return osError
			}
			// umount destination filesystem and remove temp mount point.
			defer os.Remove(config.DestDir)
			defer umountDestDev(config, outLog)
			// For some reason, not having a pause before attempting to unmount
			// can generate a race condition where umount complains that the fs
			// is busy (even though the transport is already down.)
			defer time.Sleep(2 * time.Second)
		}
	}

	// Create new transport based on config.Transport
	switch config.Transport {
	case "rclone":
		transp, err = transports.NewRcloneTransport(config, nil, outLog, int(opt.verbose), opt.dryrun)
	case "rdiff-backup":
		transp, err = transports.NewRdiffBackupTransport(config, nil, outLog, int(opt.verbose), opt.dryrun)
	case "rsync":
		transp, err = transports.NewRsyncTransport(config, nil, outLog, int(opt.verbose), opt.dryrun)
	default:
		log.Printf("Unknown transport %q", config.Transport)
		return osError
	}
	if err != nil {
		log.Printf("Error creating %s transport: %v", config.Transport, err)
		return osError
	}

	// Execute pre-commands, if any.
	if err := runCommand("PRE", config.PreCommand, nil, outLog); err != nil {
		log.Printf("Error running pre-command: %v", err)
		return osError
	}

	// Make it so...
	if err := transp.Run(); err != nil {
		log.Printf("Error running backup: %v", err)
		return osError
	}
	fmt.Fprintf(outLog, "*** Backup Result: Success\n")

	// Execute post-commands, if any.
	if err := runCommand("POST", config.PostCommand, nil, outLog); err != nil {
		fmt.Fprintf(outLog, "*** Backup Result: Failure (%v)\n", err)
		log.Printf("Error running post-command: %v", err)
		return osError
	}

	return osSuccess
}

func main() {
	os.Exit(backup())
}
<commit_msg>Run df at the end of the backups and log output.<commit_after>// netbackup - Consistent multi-method backup tool
//
// See instructions in the README.md file that accompanies this program.
//
// (C) 2015 by Marco Paganini <paganini AT paganini DOT net>

package main

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"time"

	"github.com/marcopaganini/logger"
	"github.com/marcopaganini/netbackup/config"
	"github.com/marcopaganini/netbackup/execute"
	"github.com/marcopaganini/netbackup/transports"
)

const (
	defaultLogDir = "/tmp/log/netbackup"
	devMapperDir  = "/dev/mapper"

	// Default permissions for log directories and files.
	// The current umask will apply to these.
	defaultLogDirMode  = 0777
	defaultLogFileMode = 0666

	// Return codes
	osSuccess = 0
	osError   = 1

	// External commands.
	mountCmd      = "mount"
	umountCmd     = "umount"
	cryptSetupCmd = "cryptsetup"
	fsckCmd       = "fsck"
	tunefsCmd     = "tune2fs"
	dfCmd         = "df"
)

var (
	// Generic logging object
	log *logger.Logger
)

// usage prints an error message and program usage to stderr, exiting after
// that.
func usage(err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %v\n\n", err)
	}
	fmt.Fprintf(os.Stderr, "Usage%s:\n", os.Args[0])
	flag.PrintDefaults()
	os.Exit(2)
}

// createOutputLog creates a new output log file. If logPath is set, it is used
// unchanged. If not, a new log is created based under logDir using the
// configuration name, and the system date. Intermediate directories are
// created as needed. Returns a *os.File, the file created, error.
func createOutputLog(logPath string, logDir string, configName string) (*os.File, string, error) {
	path := logPath
	if path == "" {
		dir := filepath.Join(logDir, configName)
		if err := os.MkdirAll(dir, defaultLogDirMode); err != nil {
			return nil, "", fmt.Errorf("Error trying to create dir tree %q: %v", dir, err)
		}
		ymd := time.Now().Format("2006-01-02")
		path = filepath.Join(dir, configName+"-"+ymd+".log")
	}

	w, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, defaultLogFileMode)
	if err != nil {
		return nil, path, fmt.Errorf("Error opening %q: %v", path, err)
	}
	return w, path, err
}

// shellRun run a command string using the shell using the specified execute object.
func shellRun(e *execute.Execute, cmd string) error {
	shell := os.Getenv("SHELL")
	if shell == "" {
		shell = "/bin/sh"
	}
	a := []string{shell, "-c", "--", cmd}
	return e.Exec(a)
}

// runCommand executes the pre or post commands using the shell. A prefix will
// be used to log the commands to the output log (usually, "PRE" for
// pre-commands or "POST" for post-commands Returns error.
func runCommand(prefix string, cmd string, ex *execute.Execute, outLog io.Writer) error {
	m := fmt.Sprintf("%s Command: %q", prefix, cmd)
	log.Verboseln(int(opt.verbose), m)
	if opt.dryrun {
		return nil
	}

	// Create a new execute object, if current is nil
	e := ex
	if e == nil {
		e = execute.New()
	}

	// All streams copied to output log with "PRE:" as a prefix.
	e.SetStdout(func(buf string) error { _, err := fmt.Fprintf(outLog, "%s(stdout): %s\n", prefix, buf); return err })
	e.SetStderr(func(buf string) error { _, err := fmt.Fprintf(outLog, "%s(stderr): %s\n", prefix, buf); return err })

	fmt.Fprintf(outLog, "*** %s\n", m)
	err := shellRun(e, cmd)
	fmt.Fprintf(outLog, "*** %s returned: %v\n", prefix, err)

	return err
}

// mountDestDev mounts the destination device specified in config.DestDev into
// a temporary mount point and set config.DestDir to point to this directory.
func mountDestDev(config *config.Config, outLog io.Writer) error {
	tmpdir, err := ioutil.TempDir("", "netbackup_mount")
	if err != nil {
		return fmt.Errorf("unable to create temp directory: %v", err)
	}

	// We use the mount command instead of the mount syscal as it makes
	// simpler to specify defaults in /etc/fstab.
	cmd := mountCmd + " " + config.DestDev + " " + tmpdir
	if err := runCommand("MOUNT", cmd, nil, outLog); err != nil {
		return fmt.Errorf("error running %q: %v", cmd, err)
	}

	config.DestDir = tmpdir
	return nil
}

// umountDestDev dismounts the destination device specified in config.DestDev.
func umountDestDev(config *config.Config, outLog io.Writer) error {
	cmd := umountCmd + " " + config.DestDev
	if err := runCommand("UMOUNT", cmd, nil, outLog); err != nil {
		return fmt.Errorf("error running %q: %v", cmd, err)
	}
	return nil
}

// openLuksDestDev opens the luks device specified by config.LuksDestDev and sets
// config.DestDev to the /dev/mapper device.
func openLuksDestDev(config *config.Config, outLog io.Writer) error {
	// Our temporary dev/mapper device is based on the config name
	devname := "netbackup_" + config.Name
	devfile := filepath.Join(devMapperDir, devname)

	// Make sure it doesn't already exist
	if _, err := os.Stat(devfile); err == nil {
		return fmt.Errorf("device mapper file %q already exists.", devfile)
	}

	// cryptsetup LuksOpen
	cmd := cryptSetupCmd
	if config.LuksKeyFile != "" {
		cmd += " --key-file " + config.LuksKeyFile
	}
	cmd += " luksOpen " + config.LuksDestDev + " " + devname
	if err := runCommand("LUKS_OPEN", cmd, nil, outLog); err != nil {
		return fmt.Errorf("error running %q: %v", cmd, err)
	}

	// Set the destination device to devfile so the normal processing
	// will be sufficient to mount and dismount this device.
	config.DestDev = devfile
	return nil
}

// closeLuksDestDev closes the luks device specified by config.LuksDestDev.
func closeLuksDestDev(config *config.Config, outLog io.Writer) error {
	// Note that even though this function is called closeLuksDestDev we use
	// the mount point under /dev/mapper to close the device.  The mount point
	// was previously set by openLuksDestDev.
	cmd := cryptSetupCmd + " luksClose " + config.DestDev
	if err := runCommand("LUKS_CLOSE", cmd, nil, outLog); err != nil {
		return fmt.Errorf("error running %q: %v", cmd, err)
	}
	return nil
}

// displayDiskSpace runs "df" on the system and writes the output to the logfile.
func displayDiskSpace(config *config.Config, outLog io.Writer) error {
	cmd := dfCmd + " -m"
	if err := runCommand("DF", cmd, nil, outLog); err != nil {
		return fmt.Errorf("error running %q: %v", cmd, err)
	}
	return nil
}

// fsCleanup runs fsck to make sure the filesystem under config.dest_dev is
// intact, and sets the number of times to check to 0 and the last time
// checked to now. This option should only be used in EXTn filesystems or
// filesystems that support tunefs.
func fsCleanup(config *config.Config, outLog io.Writer) error {
	// fsck (read-only check)
	cmd := fsckCmd + " -n " + config.DestDev
	if err := runCommand("FS_CLEANUP", cmd, nil, outLog); err != nil {
		return fmt.Errorf("error running %q: %v", cmd, err)
	}
	// Tunefs
	cmd = tunefsCmd + " -C 0 -T now " + config.DestDev
	if err := runCommand("FS_CLEANUP", cmd, nil, outLog); err != nil {
		return fmt.Errorf("error running %q: %v", cmd, err)
	}
	return nil
}

func backup() int {
	var transp interface {
		Run() error
	}
	log = logger.New("")

	// Parse command line flags and read config file.
	if err := parseFlags(); err != nil {
		log.Printf("Error: %v", err)
		return osError
	}
	// Set verbose level
	if opt.verbose > 0 {
		log.SetVerboseLevel(int(opt.verbose))
	}
	if opt.dryrun {
		log.Verbosef(2, "Warning: Dry-Run mode. Won't execute any commands.")
	}

	// Open and parse config file
	cfg, err := os.Open(opt.config)
	if err != nil {
		log.Printf("Unable to open config file: %v", err)
		return osError
	}
	config, err := config.ParseConfig(cfg)
	if err != nil {
		log.Printf("Configuration error in %q: %v", opt.config, err)
		return osError
	}

	// Open or create the output log file. This log will contain a transcript
	// of stdout and stderr from all commands executed by this program.
	outLog, outPath, err := createOutputLog(config.Logfile, defaultLogDir, config.Name)
	if err != nil {
		log.Printf("Error opening output logfile: %q: %v", outPath, err)
		return osError
	}
	defer outLog.Close()

	if !opt.dryrun {
		// Open LUKS device, if needed
		if config.LuksDestDev != "" {
			if err := openLuksDestDev(config, outLog); err != nil {
				log.Printf("Error opening LUKS device %q: %v", config.LuksDestDev, err)
				return osError
			}
			// close luks device at the end
			defer closeLuksDestDev(config, outLog)
			defer time.Sleep(2 * time.Second)
		}

		// Run cleanup on fs prior to backup, if requested.
		if config.FSCleanup {
			if err := fsCleanup(config, outLog); err != nil {
				log.Printf("Error performing pre-backup cleanup on %q: %v", config.DestDev, err)
				return osError
			}
		}

		// Mount destination device, if needed.
		if config.DestDev != "" {
			if err := mountDestDev(config, outLog); err != nil {
				log.Printf("Error opening destination device %q: %v", config.DestDev, err)
				return osError
			}
			// umount destination filesystem and remove temp mount point.
			defer os.Remove(config.DestDir)
			defer umountDestDev(config, outLog)
			// For some reason, not having a pause before attempting to unmount
			// can generate a race condition where umount complains that the fs
			// is busy (even though the transport is already down.)
			defer time.Sleep(2 * time.Second)
		}
	}

	// Create new transport based on config.Transport
	switch config.Transport {
	case "rclone":
		transp, err = transports.NewRcloneTransport(config, nil, outLog, int(opt.verbose), opt.dryrun)
	case "rdiff-backup":
		transp, err = transports.NewRdiffBackupTransport(config, nil, outLog, int(opt.verbose), opt.dryrun)
	case "rsync":
		transp, err = transports.NewRsyncTransport(config, nil, outLog, int(opt.verbose), opt.dryrun)
	default:
		log.Printf("Unknown transport %q", config.Transport)
		return osError
	}
	if err != nil {
		log.Printf("Error creating %s transport: %v", config.Transport, err)
		return osError
	}

	// Execute pre-commands, if any.
	if err := runCommand("PRE", config.PreCommand, nil, outLog); err != nil {
		log.Printf("Error running pre-command: %v", err)
		return osError
	}

	// Make it so...
	if err := transp.Run(); err != nil {
		log.Printf("Error running backup: %v", err)
		return osError
	}
	fmt.Fprintf(outLog, "*** Backup Result: Success\n")

	// Execute post-commands, if any.
	if err := runCommand("POST", config.PostCommand, nil, outLog); err != nil {
		fmt.Fprintf(outLog, "*** Backup Result: Failure (%v)\n", err)
		log.Printf("Error running post-command: %v", err)
		return osError
	}

	// Log df output (best effort)
	displayDiskSpace(config, outLog)

	return osSuccess
}

func main() {
	os.Exit(backup())
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"

	"github.com/herald-it/goncord/controllers"
	"github.com/herald-it/goncord/models"
	. "github.com/herald-it/goncord/utils"

	"net/http"

	"github.com/julienschmidt/httprouter"
	"gopkg.in/mgo.v2"
)

var (
	settingPath = flag.String("s", "./settings.yml", "setting file path")
)

func getSession() *mgo.Session {
	s, err := mgo.Dial(models.Set.Database.Host)
	if err != nil {
		panic(err)
	}

	return s
}

func init() {
	flag.Parse()

	if err := models.LoadSettings(*settingPath); err != nil {
		panic(err)
	}
}

func main() {
	log.Println("Start initialize...")

	uc := controllers.NewUserController(getSession())
	us := controllers.NewServiceController(getSession())

	var router = httprouter.New()

	router.POST(models.Set.Router.Register, ErrWrap(uc.RegisterUser))
	router.POST(models.Set.Router.Login, ErrWrap(uc.LoginUser))
	router.POST(models.Set.Router.Validate, ErrWrap(us.IsValid))
	router.POST(models.Set.Router.Logout, ErrWrap(us.Logout))

	router.GET("/", func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
		w.Write([]byte("Service authorization"))
	})

	log.Println("Start auth gate!")
	if err := http.ListenAndServe(models.Set.IP, router); err != nil {
		panic(err)
	}
}
<commit_msg>Add permissiom middleware on handler functions.<commit_after>package main

import (
	"flag"
	"log"

	"github.com/herald-it/goncord/controllers"
	"github.com/herald-it/goncord/models"
	. "github.com/herald-it/goncord/utils"

	"net/http"

	"github.com/herald-it/goncord/middleware"
	. "github.com/julienschmidt/httprouter"
	"gopkg.in/mgo.v2"
)

var (
	settingPath = flag.String("s", "./settings.yml", "setting file path")
)

func getSession() *mgo.Session {
	s, err := mgo.Dial(models.Set.Database.Host)
	if err != nil {
		panic(err)
	}

	return s
}

func init() {
	flag.Parse()

	if err := models.LoadSettings(*settingPath); err != nil {
		panic(err)
	}
}

func main() {
	log.Println("Start initialize...")

	uc := controllers.NewUserController(getSession())
	us := controllers.NewServiceController(getSession())

	coll := middleware.MidCollect{}
	coll = coll.Add(middleware.CheckPermission)

	router := New()
	router.POST(
		models.Set.Router.Register.Path,
		coll.Wrap(ErrWrap(uc.RegisterUser)),
	)
	router.POST(
		models.Set.Router.Login.Path,
		coll.Wrap(ErrWrap(uc.LoginUser)),
	)
	router.POST(
		models.Set.Router.Validate.Path,
		coll.Wrap(ErrWrap(us.IsValid)),
	)
	router.POST(
		models.Set.Router.Logout.Path,
		coll.Wrap(ErrWrap(us.Logout)),
	)

	router.GET("/", func(w http.ResponseWriter, r *http.Request, p Params) {
		w.Write([]byte("Service authorization"))
	})

	log.Println("Start auth gate!")
	if err := http.ListenAndServe(models.Set.IP, router); err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
    "github.com/urfave/cli"
    "os"
    "time"
)

func main() {
    app := cli.NewApp()
    app.Name = "pokevision"
    app.Usage = "the (unofficial) pokevision cli"
    app.Version = "1.0.0"
    app.Compiled = time.Now()
    app.Authors = []cli.Author{
        cli.Author{
            Name:  "Jacob Marshall",
            Email: "pokemon@jacobmarshall.co",
        },
    }
    app.Commands = []cli.Command{
        WatchCommand,
    }
    app.Run(os.Args)
}
<commit_msg>1.0.1<commit_after>package main

import (
    "github.com/urfave/cli"
    "os"
    "time"
)

func main() {
    app := cli.NewApp()
    app.Name = "pokevision"
    app.Usage = "the (unofficial) pokevision cli"
    app.Version = "1.0.1"
    app.Compiled = time.Now()
    app.Authors = []cli.Author{
        cli.Author{
            Name:  "Jacob Marshall",
            Email: "pokemon@jacobmarshall.co",
        },
    }
    app.Commands = []cli.Command{
        WatchCommand,
    }
    app.Run(os.Args)
}
<|endoftext|>


<commit_before>// Copyright 2015 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

// apidoc从代码注释中提取并生成api的文档。
package main

import (
	"flag"
	"fmt"
	"runtime"
	"strings"

	"github.com/caixw/apidoc/scanner"
	"github.com/issue9/term/colors"
)

const version = "0.3.17.150813"

var usage = `apidoc从代码注释中提取并生成api的文档。

命令行语法:
 apidoc [options] src doc

options:
 -h     显示当前帮助信息；
 -v     显示apidoc和go程序的版本信息；
 -langs 显示所有支持的语言类型。
 -r     是否搜索子目录，默认为true；
 -t     目标文件类型，支持的类型可以通过-langs来查看；
 -ext   需要分析的文件的扩展名，若不指定，则会根据-t参数自动生成相应的扩展名。
        若-t也未指定，则会根据src目录下的文件，自动判断-t的值。

src:
 源文件所在的目录。
doc:
 产生的文档保存的目录。

源代码采用MIT开源许可证，并发布于github:https://github.com/caixw/apidoc
`

func main() {
	var (
		h     bool
		v     bool
		langs bool
		r     bool
		t     string
		ext   string
	)

	flag.Usage = func() {
		fmt.Println(usage)
	}
	flag.BoolVar(&h, "h", false, "显示帮助信息")
	flag.BoolVar(&v, "v", false, "显示帮助信息")
	flag.BoolVar(&langs, "langs", false, "显示所有支持的语言")
	flag.BoolVar(&r, "r", true, "搜索子目录，默认为true")
	flag.StringVar(&t, "t", "", "指定源文件的类型，若不指定，系统会自行判断")
	flag.StringVar(&ext, "ext", "", "匹配的扩展名，若不指定，会根据-t的指定，自行判断")
	flag.Parse()

	switch {
	case h:
		flag.Usage()
		return
	case v:
		printVersion()
		return
	case langs:
		printLangs()
		return
	case flag.NArg() != 2:
		colors.Println(colors.Stderr, colors.Red, colors.Default, "请同时指定src和dest参数")
		return
	}

	var exts []string
	if len(ext) > 0 {
		exts = strings.Split(strings.TrimSpace(ext), ",")
	}

	docs, err := scanner.Scan(flag.Arg(0), r, t, exts)
	if err != nil {
		panic(err)
	}

	if err = docs.OutputHtml(flag.Arg(1), version); err != nil {
		panic(err)
	}
}

func printLangs() {
	fmt.Println("目前支持以下类型的代码解析:")
	langs := scanner.Langs()
	for _, l := range langs {
		fmt.Println(l)
	}
}

func printVersion() {
	colors.Print(colors.Stdout, colors.Green, colors.Default, "apidoc: ")
	colors.Println(colors.Stdout, colors.Default, colors.Default, version)
	colors.Print(colors.Stdout, colors.Green, colors.Default, "Go: ")
	goVersion := runtime.Version() + " " + runtime.GOOS + "/" + runtime.GOARCH
	colors.Println(colors.Stdout, colors.Default, colors.Default, goVersion)
}
<commit_msg>更改相应的版本号<commit_after>// Copyright 2015 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

// apidoc从代码注释中提取并生成api的文档。
package main

import (
	"flag"
	"fmt"
	"runtime"
	"strings"

	"github.com/caixw/apidoc/scanner"
	"github.com/issue9/term/colors"
)

const version = "0.4.18.150815"

var usage = `apidoc从代码注释中提取并生成api的文档。

命令行语法:
 apidoc [options] src doc

options:
 -h     显示当前帮助信息；
 -v     显示apidoc和go程序的版本信息；
 -langs 显示所有支持的语言类型。
 -r     是否搜索子目录，默认为true；
 -t     目标文件类型，支持的类型可以通过-langs来查看；
 -ext   需要分析的文件的扩展名，若不指定，则会根据-t参数自动生成相应的扩展名。
        若-t也未指定，则会根据src目录下的文件，自动判断-t的值。

src:
 源文件所在的目录。
doc:
 产生的文档保存的目录。

源代码采用MIT开源许可证，并发布于github:https://github.com/caixw/apidoc
`

func main() {
	var (
		h     bool
		v     bool
		langs bool
		r     bool
		t     string
		ext   string
	)

	flag.Usage = func() {
		fmt.Println(usage)
	}
	flag.BoolVar(&h, "h", false, "显示帮助信息")
	flag.BoolVar(&v, "v", false, "显示帮助信息")
	flag.BoolVar(&langs, "langs", false, "显示所有支持的语言")
	flag.BoolVar(&r, "r", true, "搜索子目录，默认为true")
	flag.StringVar(&t, "t", "", "指定源文件的类型，若不指定，系统会自行判断")
	flag.StringVar(&ext, "ext", "", "匹配的扩展名，若不指定，会根据-t的指定，自行判断")
	flag.Parse()

	switch {
	case h:
		flag.Usage()
		return
	case v:
		printVersion()
		return
	case langs:
		printLangs()
		return
	case flag.NArg() != 2:
		colors.Println(colors.Stderr, colors.Red, colors.Default, "请同时指定src和dest参数")
		return
	}

	var exts []string
	if len(ext) > 0 {
		exts = strings.Split(strings.TrimSpace(ext), ",")
	}

	docs, err := scanner.Scan(flag.Arg(0), r, t, exts)
	if err != nil {
		panic(err)
	}

	if err = docs.OutputHtml(flag.Arg(1), version); err != nil {
		panic(err)
	}
}

func printLangs() {
	fmt.Println("目前支持以下类型的代码解析:")
	langs := scanner.Langs()
	for _, l := range langs {
		fmt.Println(l)
	}
}

func printVersion() {
	colors.Print(colors.Stdout, colors.Green, colors.Default, "apidoc: ")
	colors.Println(colors.Stdout, colors.Default, colors.Default, version)
	colors.Print(colors.Stdout, colors.Green, colors.Default, "Go: ")
	goVersion := runtime.Version() + " " + runtime.GOOS + "/" + runtime.GOARCH
	colors.Println(colors.Stdout, colors.Default, colors.Default, goVersion)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"regexp"
	"strings"
	"sync"

	"github.com/kylelemons/go-gypsy/yaml"
	"github.com/shawnps/gr"
	"github.com/shawnps/rt"
	"github.com/shawnps/sp"
)

var (
	port        = flag.String("p", "8000", "Port number (default 8000)")
	configFile  = flag.String("c", "config.yml", "Config file (default config.yml)")
	entriesPath = flag.String("f", "entries.json", "Path to JSON storage file (default entries.json)")
)

type Entry struct {
	Id       string
	Title    string
	Link     string
	ImageURL url.URL
	Type     string
}

func parseYAML() (rtKey, grKey, grSecret string, err error) {
	config, err := yaml.ReadFile(*configFile)
	if err != nil {
		return
	}
	rtKey, err = config.Get("rt")
	if err != nil {
		return
	}
	grKey, err = config.Get("gr.key")
	if err != nil {
		return
	}
	grSecret, err = config.Get("gr.secret")
	if err != nil {
		return
	}

	return rtKey, grKey, grSecret, nil
}

func writeJSON(e []Entry, file string) error {
	b, err := json.Marshal(e)
	if err != nil {
		return err
	}
	err = ioutil.WriteFile(file, b, 0755)
	if err != nil {
		return err
	}

	return nil
}

func buildEntryMap(entries []Entry) map[string][]Entry {
	m := map[string][]Entry{}
	for _, e := range entries {
		k := strings.Title(e.Type)
		m[k] = append(m[k], e)
	}
	return m
}

func readEntries() ([]Entry, error) {
	var e []Entry
	b, err := ioutil.ReadFile(*entriesPath)
	if err != nil {
		return e, err
	}
	if len(b) == 0 {
		return []Entry{}, nil
	}
	err = json.Unmarshal(b, &e)
	if err != nil {
		return e, err
	}

	return e, nil
}

func uuid() (string, error) {
	f, err := os.Open("/dev/urandom")
	if err != nil {
		return "", err
	}
	b := make([]byte, 16)
	f.Read(b)
	f.Close()
	uuid := fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])

	return uuid, nil
}

func insertEntry(title, link, mediaType, imageURL string) error {
	if _, err := os.Stat(*entriesPath); os.IsNotExist(err) {
		_, err := os.Create(*entriesPath)
		if err != nil {
			return err
		}
		err = writeJSON([]Entry{}, *entriesPath)
		if err != nil {
			return err
		}
	}
	e, err := readEntries()
	if err != nil {
		return err
	}
	url, err := url.Parse(imageURL)
	if err != nil {
		return err
	}
	id, err := uuid()
	if err != nil {
		return err
	}
	entry := Entry{id, title, link, *url, mediaType}
	e = append(e, entry)
	err = writeJSON(e, *entriesPath)
	if err != nil {
		return err
	}
	return nil
}

func removeEntry(id string) error {
	entries, err := readEntries()
	if err != nil {
		return err
	}
	for i, e := range entries {
		if e.Id == id {
			entries = append(entries[:i], entries[i+1:]...)
		}
	}
	return writeJSON(entries, *entriesPath)
}

func truncate(s, suf string, l int) string {
	if len(s) < l {
		return s
	} else {
		return s[:l] + suf
	}
}

// Search Rotten Tomatoes, Goodreads, and Spotify.
func Search(q string, rtClient rt.RottenTomatoes, grClient gr.Goodreads, spClient sp.Spotify) (m []rt.Movie, g gr.GoodreadsResponse, s sp.SearchAlbumsResponse) {
	var wg sync.WaitGroup
	wg.Add(3)
	go func(q string) {
		defer wg.Done()
		movies, err := rtClient.SearchMovies(q)
		if err != nil {
			log.Println("ERROR (rt):", err.Error())
		}
		for _, mov := range movies {
			mov.Title = truncate(mov.Title, "...", 60)
			m = append(m, mov)
		}
	}(q)
	go func(q string) {
		defer wg.Done()
		books, err := grClient.SearchBooks(q)
		if err != nil {
			log.Println("ERROR (gr):", err.Error())
		}
		for i, w := range books.Search.Works {
			w.BestBook.Title = truncate(w.BestBook.Title, "...", 60)
			books.Search.Works[i] = w
		}
		g = books
	}(q)
	go func(q string) {
		defer wg.Done()
		albums, err := spClient.SearchAlbums(q)
		if err != nil {
			log.Println("ERROR (sp):", err.Error())
		}
		for i, a := range albums.Albums.Items {
			a.Name = truncate(a.Name, "...", 60)
			albums.Albums.Items[i] = a
		}
		s = albums
	}(q)
	wg.Wait()
	return m, g, s
}

func HomeHandler(w http.ResponseWriter, r *http.Request) {
	t, err := template.New("index.html").ParseFiles("templates/index.html", "templates/base.html")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	// Render the template
	err = t.ExecuteTemplate(w, "base", map[string]interface{}{"Page": "home"})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func SearchHandler(w http.ResponseWriter, r *http.Request, query string) {
	rtKey, grKey, grSecret, err := parseYAML()
	if err != nil {
		log.Println("ERROR:", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	client := &http.Client{}
	rtClient := rt.RottenTomatoes{client, rtKey}
	grClient := gr.Goodreads{client, grKey, grSecret}
	spClient := sp.Spotify{client}
	m, g, s := Search(query, rtClient, grClient, spClient)
	// Since spotify: URIs are not trusted, have to pass a
	// URL function to the template to use in hrefs
	funcMap := template.FuncMap{
		"URL": func(q string) template.URL { return template.URL(query) },
		"spotifyImage": func(album sp.Album) string {
			if len(album.Images) > 0 {
				return album.Images[len(album.Images)-1].URL
			}
			return ""
		},
	}
	t, err := template.New("search.html").Funcs(funcMap).ParseFiles("templates/search.html", "templates/base.html")
	if err != nil {
		log.Println("ERROR:", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	// Render the template
	err = t.ExecuteTemplate(w, "base", map[string]interface{}{"Movies": m, "Books": g, "Albums": s.Albums})
	if err != nil {
		log.Println("ERROR:", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func SaveHandler(w http.ResponseWriter, r *http.Request) {
	t := r.FormValue("title")
	l := r.FormValue("link")
	m := r.FormValue("media_type")
	url := r.FormValue("image_url")
	err := insertEntry(t, l, m, url)
	if err != nil {
		log.Println("ERROR:", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	http.Redirect(w, r, "/list", http.StatusFound)
}

func ListHandler(w http.ResponseWriter, r *http.Request) {
	e, err := readEntries()
	if err != nil {
		log.Println("ERROR:", err)
		http.Error(w, fmt.Sprintf("Error reading entries: %v", err), http.StatusInternalServerError)
		return
	}
	m := buildEntryMap(e)
	// Create and parse Template
	t, err := template.New("list.html").ParseFiles("templates/list.html", "templates/base.html")
	if err != nil {
		log.Println("ERROR:", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	// Render the template
	t.ExecuteTemplate(w, "base", map[string]interface{}{"Entries": m, "Page": "list"})
}

func RemoveHandler(w http.ResponseWriter, r *http.Request) {
	i := r.FormValue("id")
	err := removeEntry(i)
	if err != nil {
		log.Println("ERROR:", err)
		http.Error(w, fmt.Sprintf("Error reading entries: %v", err), http.StatusInternalServerError)
		return
	}
	http.Redirect(w, r, "/list", http.StatusFound)
}

var validSearchPath = regexp.MustCompile("^/search/(.*)$")

func makeSearchHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		m := validSearchPath.FindStringSubmatch(r.URL.Path)
		if m == nil {
			http.NotFound(w, r)
			return
		}
		fn(w, r, m[1])
	}
}

func main() {
	flag.Parse()
	http.HandleFunc("/", HomeHandler)
	http.HandleFunc("/search/", makeSearchHandler(SearchHandler))
	http.HandleFunc("/save", SaveHandler)
	http.HandleFunc("/list", ListHandler)
	http.HandleFunc("/remove", RemoveHandler)
	log.Println("Running on localhost:" + *port)

	log.Fatal(http.ListenAndServe(":"+*port, nil))
}
<commit_msg>fix server address mac os popup<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"regexp"
	"strings"
	"sync"

	"github.com/kylelemons/go-gypsy/yaml"
	"github.com/shawnps/gr"
	"github.com/shawnps/rt"
	"github.com/shawnps/sp"
)

var (
	port        = flag.String("p", "8000", "Port number (default 8000)")
	configFile  = flag.String("c", "config.yml", "Config file (default config.yml)")
	entriesPath = flag.String("f", "entries.json", "Path to JSON storage file (default entries.json)")
)

type Entry struct {
	Id       string
	Title    string
	Link     string
	ImageURL url.URL
	Type     string
}

func parseYAML() (rtKey, grKey, grSecret string, err error) {
	config, err := yaml.ReadFile(*configFile)
	if err != nil {
		return
	}
	rtKey, err = config.Get("rt")
	if err != nil {
		return
	}
	grKey, err = config.Get("gr.key")
	if err != nil {
		return
	}
	grSecret, err = config.Get("gr.secret")
	if err != nil {
		return
	}

	return rtKey, grKey, grSecret, nil
}

func writeJSON(e []Entry, file string) error {
	b, err := json.Marshal(e)
	if err != nil {
		return err
	}
	err = ioutil.WriteFile(file, b, 0755)
	if err != nil {
		return err
	}

	return nil
}

func buildEntryMap(entries []Entry) map[string][]Entry {
	m := map[string][]Entry{}
	for _, e := range entries {
		k := strings.Title(e.Type)
		m[k] = append(m[k], e)
	}
	return m
}

func readEntries() ([]Entry, error) {
	var e []Entry
	b, err := ioutil.ReadFile(*entriesPath)
	if err != nil {
		return e, err
	}
	if len(b) == 0 {
		return []Entry{}, nil
	}
	err = json.Unmarshal(b, &e)
	if err != nil {
		return e, err
	}

	return e, nil
}

func uuid() (string, error) {
	f, err := os.Open("/dev/urandom")
	if err != nil {
		return "", err
	}
	b := make([]byte, 16)
	f.Read(b)
	f.Close()
	uuid := fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])

	return uuid, nil
}

func insertEntry(title, link, mediaType, imageURL string) error {
	if _, err := os.Stat(*entriesPath); os.IsNotExist(err) {
		_, err := os.Create(*entriesPath)
		if err != nil {
			return err
		}
		err = writeJSON([]Entry{}, *entriesPath)
		if err != nil {
			return err
		}
	}
	e, err := readEntries()
	if err != nil {
		return err
	}
	url, err := url.Parse(imageURL)
	if err != nil {
		return err
	}
	id, err := uuid()
	if err != nil {
		return err
	}
	entry := Entry{id, title, link, *url, mediaType}
	e = append(e, entry)
	err = writeJSON(e, *entriesPath)
	if err != nil {
		return err
	}
	return nil
}

func removeEntry(id string) error {
	entries, err := readEntries()
	if err != nil {
		return err
	}
	for i, e := range entries {
		if e.Id == id {
			entries = append(entries[:i], entries[i+1:]...)
		}
	}
	return writeJSON(entries, *entriesPath)
}

func truncate(s, suf string, l int) string {
	if len(s) < l {
		return s
	} else {
		return s[:l] + suf
	}
}

// Search Rotten Tomatoes, Goodreads, and Spotify.
func Search(q string, rtClient rt.RottenTomatoes, grClient gr.Goodreads, spClient sp.Spotify) (m []rt.Movie, g gr.GoodreadsResponse, s sp.SearchAlbumsResponse) {
	var wg sync.WaitGroup
	wg.Add(3)
	go func(q string) {
		defer wg.Done()
		movies, err := rtClient.SearchMovies(q)
		if err != nil {
			log.Println("ERROR (rt):", err.Error())
		}
		for _, mov := range movies {
			mov.Title = truncate(mov.Title, "...", 60)
			m = append(m, mov)
		}
	}(q)
	go func(q string) {
		defer wg.Done()
		books, err := grClient.SearchBooks(q)
		if err != nil {
			log.Println("ERROR (gr):", err.Error())
		}
		for i, w := range books.Search.Works {
			w.BestBook.Title = truncate(w.BestBook.Title, "...", 60)
			books.Search.Works[i] = w
		}
		g = books
	}(q)
	go func(q string) {
		defer wg.Done()
		albums, err := spClient.SearchAlbums(q)
		if err != nil {
			log.Println("ERROR (sp):", err.Error())
		}
		for i, a := range albums.Albums.Items {
			a.Name = truncate(a.Name, "...", 60)
			albums.Albums.Items[i] = a
		}
		s = albums
	}(q)
	wg.Wait()
	return m, g, s
}

func HomeHandler(w http.ResponseWriter, r *http.Request) {
	t, err := template.New("index.html").ParseFiles("templates/index.html", "templates/base.html")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	// Render the template
	err = t.ExecuteTemplate(w, "base", map[string]interface{}{"Page": "home"})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func SearchHandler(w http.ResponseWriter, r *http.Request, query string) {
	rtKey, grKey, grSecret, err := parseYAML()
	if err != nil {
		log.Println("ERROR:", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	client := &http.Client{}
	rtClient := rt.RottenTomatoes{client, rtKey}
	grClient := gr.Goodreads{client, grKey, grSecret}
	spClient := sp.Spotify{client}
	m, g, s := Search(query, rtClient, grClient, spClient)
	// Since spotify: URIs are not trusted, have to pass a
	// URL function to the template to use in hrefs
	funcMap := template.FuncMap{
		"URL": func(q string) template.URL { return template.URL(query) },
		"spotifyImage": func(album sp.Album) string {
			if len(album.Images) > 0 {
				return album.Images[len(album.Images)-1].URL
			}
			return ""
		},
	}
	t, err := template.New("search.html").Funcs(funcMap).ParseFiles("templates/search.html", "templates/base.html")
	if err != nil {
		log.Println("ERROR:", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	// Render the template
	err = t.ExecuteTemplate(w, "base", map[string]interface{}{"Movies": m, "Books": g, "Albums": s.Albums})
	if err != nil {
		log.Println("ERROR:", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func SaveHandler(w http.ResponseWriter, r *http.Request) {
	t := r.FormValue("title")
	l := r.FormValue("link")
	m := r.FormValue("media_type")
	url := r.FormValue("image_url")
	err := insertEntry(t, l, m, url)
	if err != nil {
		log.Println("ERROR:", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	http.Redirect(w, r, "/list", http.StatusFound)
}

func ListHandler(w http.ResponseWriter, r *http.Request) {
	e, err := readEntries()
	if err != nil {
		log.Println("ERROR:", err)
		http.Error(w, fmt.Sprintf("Error reading entries: %v", err), http.StatusInternalServerError)
		return
	}
	m := buildEntryMap(e)
	// Create and parse Template
	t, err := template.New("list.html").ParseFiles("templates/list.html", "templates/base.html")
	if err != nil {
		log.Println("ERROR:", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	// Render the template
	t.ExecuteTemplate(w, "base", map[string]interface{}{"Entries": m, "Page": "list"})
}

func RemoveHandler(w http.ResponseWriter, r *http.Request) {
	i := r.FormValue("id")
	err := removeEntry(i)
	if err != nil {
		log.Println("ERROR:", err)
		http.Error(w, fmt.Sprintf("Error reading entries: %v", err), http.StatusInternalServerError)
		return
	}
	http.Redirect(w, r, "/list", http.StatusFound)
}

var validSearchPath = regexp.MustCompile("^/search/(.*)$")

func makeSearchHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		m := validSearchPath.FindStringSubmatch(r.URL.Path)
		if m == nil {
			http.NotFound(w, r)
			return
		}
		fn(w, r, m[1])
	}
}

func main() {
	flag.Parse()
	http.HandleFunc("/", HomeHandler)
	http.HandleFunc("/search/", makeSearchHandler(SearchHandler))
	http.HandleFunc("/save", SaveHandler)
	http.HandleFunc("/list", ListHandler)
	http.HandleFunc("/remove", RemoveHandler)
	log.Println("Running on localhost:" + *port)

	log.Fatal(http.ListenAndServe("127.0.0.1:"+*port, nil))
}
<|endoftext|>


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

package main

import (
	"fmt"
	"io/ioutil"
	"os"

	"github.com/juju/cmd"
	"github.com/juju/errors"
	"github.com/juju/loggo"
	"github.com/juju/names"
	"gopkg.in/yaml.v2"
	"launchpad.net/gnuflag"

	"github.com/juju/juju/agent"
	"github.com/juju/juju/environs"
	"github.com/juju/juju/mongo"
	"github.com/juju/juju/state"
	"github.com/juju/juju/state/migration"
)

var logger = loggo.GetLogger("juju")

func main() {
	ctx, err := cmd.DefaultContext()
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(2)
	}
	os.Exit(cmd.Main(&MigrateCommand{}, ctx, os.Args[1:]))
}

type MigrateCommand struct {
	cmd.CommandBase

	operation  string
	dataDir    string
	modelUUID  string
	machineId  string
	filename   string
	machineTag names.MachineTag
}

func (c *MigrateCommand) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "migration-test",
		Args:    "[export <uuid>]|[import yamlfile]",
		Purpose: "run the missing upgrade steps",
	}
}

func (c *MigrateCommand) SetFlags(f *gnuflag.FlagSet) {
	f.StringVar(&c.dataDir, "data-dir", "/var/lib/juju", "directory for juju data")
	f.StringVar(&c.machineId, "machine", "0", "id of the machine you are on")
}

func (c *MigrateCommand) Init(args []string) error {
	if len(args) == 0 {
		return errors.New("missing operation")
	}
	c.operation, args = args[0], args[1:]

	switch c.operation {
	case "export":
		if len(args) == 0 {
			return errors.New("missing model uuid")
		}
		c.modelUUID, args = args[0], args[1:]

	case "import":
		if len(args) == 0 {
			return errors.New("missing yaml filename")
		}
		c.filename, args = args[0], args[1:]
	default:
		return errors.Errorf("unknown operation %q", c.operation)
	}

	if !names.IsValidMachine(c.machineId) {
		return errors.Errorf("%q is not a valid machine id", c.machineId)
	}
	c.machineTag = names.NewMachineTag(c.machineId)
	return cmd.CheckEmpty(args)
}

func (c *MigrateCommand) Run(ctx *cmd.Context) error {

	loggo.GetLogger("juju").SetLogLevel(loggo.DEBUG)
	conf, err := agent.ReadConfig(agent.ConfigPath(c.dataDir, c.machineTag))
	if err != nil {
		return err
	}

	info, ok := conf.MongoInfo()
	if !ok {
		return errors.Errorf("no state info available")
	}
	st, err := state.Open(conf.Environment(), info, mongo.DefaultDialOpts(), environs.NewStatePolicy())
	if err != nil {
		return err
	}
	defer st.Close()

	if c.operation == "export" {
		return c.exportModel(ctx, st)
	}

	return c.importModel(ctx, st)

}

func (c *MigrateCommand) exportModel(ctx *cmd.Context, st *state.State) error {
	ctx.Infof("\nexport %s", c.modelUUID)

	// first make sure the uuid is good enough
	tag := names.NewEnvironTag(c.modelUUID)
	_, err := st.GetEnvironment(tag)
	if err != nil {
		return errors.Trace(err)
	}

	modelState, err := st.ForEnviron(tag)
	if err != nil {
		return errors.Trace(err)
	}
	defer modelState.Close()

	model, err := modelState.Export()
	if err != nil {
		return errors.Trace(err)
	}

	bytes, err := yaml.Marshal(model)
	if err != nil {
		return errors.Trace(err)
	}

	ctx.Stdout.Write(bytes)
	return nil
}

func (c *MigrateCommand) importModel(ctx *cmd.Context, st *state.State) error {
	ctx.Infof("\nimport ")

	bytes, err := ioutil.ReadFile(c.filename)
	if err != nil {
		return errors.Trace(err)
	}

	model, err := migration.DeserializeModel(bytes)
	if err != nil {
		return errors.Trace(err)
	}

	env, newSt, err := st.Import(model)
	if err != nil {
		return errors.Trace(err)
	}
	defer newSt.Close()

	ctx.Infof("success, env %s/%s imported", env.Owner().Canonical(), env.Name())

	return nil
}
<commit_msg>Updated for tip of model-migration.<commit_after>// Copyright 2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package main

import (
	"fmt"
	"io/ioutil"
	"os"

	"github.com/juju/cmd"
	"github.com/juju/errors"
	"github.com/juju/loggo"
	"github.com/juju/names"
	"gopkg.in/yaml.v2"
	"launchpad.net/gnuflag"

	"github.com/juju/juju/agent"
	"github.com/juju/juju/environs"
	"github.com/juju/juju/migration"
	"github.com/juju/juju/mongo"
	"github.com/juju/juju/state"
)

var logger = loggo.GetLogger("juju")

func main() {
	ctx, err := cmd.DefaultContext()
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(2)
	}
	os.Exit(cmd.Main(&MigrateCommand{}, ctx, os.Args[1:]))
}

type MigrateCommand struct {
	cmd.CommandBase

	operation  string
	dataDir    string
	modelUUID  string
	machineId  string
	filename   string
	machineTag names.MachineTag
}

func (c *MigrateCommand) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "migration-test",
		Args:    "[export <uuid>]|[import yamlfile]",
		Purpose: "run the missing upgrade steps",
	}
}

func (c *MigrateCommand) SetFlags(f *gnuflag.FlagSet) {
	f.StringVar(&c.dataDir, "data-dir", "/var/lib/juju", "directory for juju data")
	f.StringVar(&c.machineId, "machine", "0", "id of the machine you are on")
}

func (c *MigrateCommand) Init(args []string) error {
	if len(args) == 0 {
		return errors.New("missing operation")
	}
	c.operation, args = args[0], args[1:]

	switch c.operation {
	case "export":
		if len(args) == 0 {
			return errors.New("missing model uuid")
		}
		c.modelUUID, args = args[0], args[1:]

	case "import":
		if len(args) == 0 {
			return errors.New("missing yaml filename")
		}
		c.filename, args = args[0], args[1:]
	default:
		return errors.Errorf("unknown operation %q", c.operation)
	}

	if !names.IsValidMachine(c.machineId) {
		return errors.Errorf("%q is not a valid machine id", c.machineId)
	}
	c.machineTag = names.NewMachineTag(c.machineId)
	return cmd.CheckEmpty(args)
}

func (c *MigrateCommand) Run(ctx *cmd.Context) (err error) {

	defer func() {
		if err != nil {
			fmt.Fprintf(ctx.Stdout, "error stack:\n"+errors.ErrorStack(err))
		}
	}()

	loggo.GetLogger("juju").SetLogLevel(loggo.DEBUG)
	conf, err := agent.ReadConfig(agent.ConfigPath(c.dataDir, c.machineTag))
	if err != nil {
		return err
	}

	info, ok := conf.MongoInfo()
	if !ok {
		return errors.Errorf("no state info available")
	}
	st, err := state.Open(conf.Model(), info, mongo.DefaultDialOpts(), environs.NewStatePolicy())
	if err != nil {
		return err
	}
	defer st.Close()

	if c.operation == "export" {
		return c.exportModel(ctx, st)
	}

	return c.importModel(ctx, st)

}

func (c *MigrateCommand) exportModel(ctx *cmd.Context, st *state.State) error {
	ctx.Infof("\nexport %s", c.modelUUID)

	// first make sure the uuid is good enough
	tag := names.NewModelTag(c.modelUUID)
	_, err := st.GetModel(tag)
	if err != nil {
		return errors.Trace(err)
	}

	modelState, err := st.ForModel(tag)
	if err != nil {
		return errors.Trace(err)
	}
	defer modelState.Close()

	model, err := modelState.Export()
	if err != nil {
		return errors.Trace(err)
	}

	bytes, err := yaml.Marshal(model)
	if err != nil {
		return errors.Trace(err)
	}

	ctx.Stdout.Write(bytes)
	return nil
}

func (c *MigrateCommand) importModel(ctx *cmd.Context, st *state.State) error {
	ctx.Infof("\nimport ")

	bytes, err := ioutil.ReadFile(c.filename)
	if err != nil {
		return errors.Trace(err)
	}

	env, newSt, err := migration.ImportModel(st, bytes)
	if err != nil {
		return errors.Trace(err)
	}
	defer newSt.Close()

	ctx.Infof("success, model %s/%s imported", env.Owner().Canonical(), env.Name())

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	sinaiplib "github.com/ifduyue/sinaip-go/lib"
	"log"
	"os"
	"runtime"
)

var (
	sinaip    *sinaiplib.SINAIP
	cpus      *int
	ipdatpath *string
	preload   *bool
)

func main() {
	commands := map[string]command{"httpd": httpdCmd(), "query": queryCmd()}

	flag.Usage = func() {
		fmt.Println("Usage: sinaip-go [globals] <command> [options]")
		for name, cmd := range commands {
			fmt.Printf("\n%s command: %s\n", name, cmd.usage)
			cmd.fs.PrintDefaults()
		}
		fmt.Printf("\nglobal flags:\n")
		fmt.Printf("\t-cpus=%d Number of CPUs to use\n", runtime.NumCPU())
		fmt.Printf("\t-ipdat=\"\" Path to ip.dat, will try to get it from env variable \"SINAIPDAT\" if left empty.\n")
		fmt.Printf("\t-preload If true, preload ip.dat into memory, otherwise mmap is used.\n")
		fmt.Println(examples)
	}

	cpus = flag.Int("cpus", runtime.NumCPU(), "Number of CPUs to use")
	ipdatpath = flag.String("ipdat", os.Getenv("SINAIPDAT"), "Path to ip.dat")
	preload = flag.Bool("preload", false, "Preload ip.dat to memory, otherwise mmap is used.")
	flag.Parse()

	args := flag.Args()
	if len(args) == 0 {
		flag.Usage()
		os.Exit(1)
	}

	runtime.GOMAXPROCS(*cpus)
	if *ipdatpath == "" {
		log.Fatal("Path to ip.dat can't be empty")
	}

	if sinaiptmp, err := sinaiplib.NewSINAIP(*ipdatpath, *preload); err != nil {
		log.Fatal(err)
	} else {
		sinaip = sinaiptmp
	}

	if cmd, ok := commands[args[0]]; !ok {
		log.Fatalf("Unknown command: %s", args[0])
	} else if err := cmd.fn(args[1:]); err != nil {
		log.Fatal(err)
	}
}

const examples = `
examples:
\tsinaip-go query 1.2.3.4
\tsinaip-go httpd 127.0.0.1:8080
`

type command struct {
	fs    *flag.FlagSet
	usage string
	fn    func(args []string) error
}
<commit_msg>Revert "Align ``--help`` output"<commit_after>package main

import (
	"flag"
	"fmt"
	sinaiplib "github.com/ifduyue/sinaip-go/lib"
	"log"
	"os"
	"runtime"
)

var (
	sinaip    *sinaiplib.SINAIP
	cpus      *int
	ipdatpath *string
	preload   *bool
)

func main() {
	commands := map[string]command{"httpd": httpdCmd(), "query": queryCmd()}

	flag.Usage = func() {
		fmt.Println("Usage: sinaip-go [globals] <command> [options]")
		for name, cmd := range commands {
			fmt.Printf("\n%s command: %s\n", name, cmd.usage)
			cmd.fs.PrintDefaults()
		}
		fmt.Printf("\nglobal flags:\n")
		fmt.Printf("\t-cpus=%d Number of CPUs to use\n", runtime.NumCPU())
		fmt.Printf("\t-ipdat=\"\" Path to ip.dat, will try to get it from env variable \"SINAIPDAT\" if left empty.\n")
		fmt.Printf("\t-preload If true, preload ip.dat into memory, otherwise mmap is used.\n")
		fmt.Println(examples)
	}

	cpus = flag.Int("cpus", runtime.NumCPU(), "Number of CPUs to use")
	ipdatpath = flag.String("ipdat", os.Getenv("SINAIPDAT"), "Path to ip.dat")
	preload = flag.Bool("preload", false, "Preload ip.dat to memory, otherwise mmap is used.")
	flag.Parse()

	args := flag.Args()
	if len(args) == 0 {
		flag.Usage()
		os.Exit(1)
	}

	runtime.GOMAXPROCS(*cpus)
	if *ipdatpath == "" {
		log.Fatal("Path to ip.dat can't be empty")
	}

	if sinaiptmp, err := sinaiplib.NewSINAIP(*ipdatpath, *preload); err != nil {
		log.Fatal(err)
	} else {
		sinaip = sinaiptmp
	}

	if cmd, ok := commands[args[0]]; !ok {
		log.Fatalf("Unknown command: %s", args[0])
	} else if err := cmd.fn(args[1:]); err != nil {
		log.Fatal(err)
	}
}

const examples = `
examples:
	sinaip-go query 1.2.3.4
	sinaip-go httpd 127.0.0.1:8080
`

type command struct {
	fs    *flag.FlagSet
	usage string
	fn    func(args []string) error
}
<|endoftext|>


<commit_before>package main

//go:generate ./version.sh

import (
	"log"
	"net/http"
	"time"

	"github.com/codegangsta/cli"
	"github.com/mozilla-services/go-bouncer/bouncer"
	_ "github.com/mozilla-services/go-bouncer/mozlog"
)

func main() {
	app := cli.NewApp()
	app.Name = "bouncer"
	app.Action = Main
	app.Version = bouncer.Version
	app.Flags = []cli.Flag{
		cli.IntFlag{
			Name:  "cache-time",
			Value: 60,
			Usage: "Time, in seconds, for Cache-Control max-age",
		},
		cli.StringFlag{
			Name:   "addr",
			Value:  ":8888",
			Usage:  "address on which to listen",
			EnvVar: "BOUNCER_ADDR",
		},
		cli.StringFlag{
			Name:   "db-dsn",
			Value:  "user:password@tcp(localhost:3306)/bouncer",
			Usage:  "database DSN (https://github.com/go-sql-driver/mysql#dsn-data-source-name)",
			EnvVar: "BOUNCER_DB_DSN",
		},
		cli.StringFlag{
			Name:   "pinned-baseurl-http",
			Usage:  "if this flag is set it will always be the base url for http products. Scheme should be excluded, e.g.,: pinned-cdn.mozilla.com/pub",
			EnvVar: "BOUNCER_PINNED_BASEURL_HTTP",
		},
		cli.StringFlag{
			Name:   "pinned-baseurl-https",
			Usage:  "if this flag is set it will always be the base url for https products. Scheme should be excluded, e.g.,: pinned-cdn.mozilla.com/pub",
			EnvVar: "BOUNCER_PINNED_BASEURL_HTTPS",
		},
		cli.StringFlag{
			Name:   "stub-root-url",
			Value:  "https://stubdownloader.prod.mozaws.net/",
			Usage:  "Root url of service used to service modified stub installers",
			EnvVar: "STUB_ROOT_URL",
		},
	}
	app.RunAndExitOnError()
}

func Main(c *cli.Context) {
	db, err := bouncer.NewDB(c.String("db-dsn"))
	if err != nil {
		log.Fatalf("Could not open DB: %v", err)
	}
	defer db.Close()

	bouncerHandler := &BouncerHandler{
		db:                 db,
		CacheTime:          time.Duration(c.Int("cache-time")) * time.Second,
		PinnedBaseURLHttp:  c.String("pinned-baseurl-http"),
		PinnedBaseURLHttps: c.String("pinned-baseurl-https"),
		StubRootURL:        c.String("stub-root-url"),
	}

	healthHandler := &HealthHandler{
		db:        db,
		CacheTime: 5 * time.Second,
	}

	mux := http.NewServeMux()

	mux.Handle("/__heartbeat__", healthHandler)
	mux.Handle("/", bouncerHandler)

	server := &http.Server{
		Addr:    c.String("addr"),
		Handler: mux,
	}

	err = server.ListenAndServe()
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>stub-root-url: default to ""<commit_after>package main

//go:generate ./version.sh

import (
	"log"
	"net/http"
	"time"

	"github.com/codegangsta/cli"
	"github.com/mozilla-services/go-bouncer/bouncer"
	_ "github.com/mozilla-services/go-bouncer/mozlog"
)

func main() {
	app := cli.NewApp()
	app.Name = "bouncer"
	app.Action = Main
	app.Version = bouncer.Version
	app.Flags = []cli.Flag{
		cli.IntFlag{
			Name:  "cache-time",
			Value: 60,
			Usage: "Time, in seconds, for Cache-Control max-age",
		},
		cli.StringFlag{
			Name:   "addr",
			Value:  ":8888",
			Usage:  "address on which to listen",
			EnvVar: "BOUNCER_ADDR",
		},
		cli.StringFlag{
			Name:   "db-dsn",
			Value:  "user:password@tcp(localhost:3306)/bouncer",
			Usage:  "database DSN (https://github.com/go-sql-driver/mysql#dsn-data-source-name)",
			EnvVar: "BOUNCER_DB_DSN",
		},
		cli.StringFlag{
			Name:   "pinned-baseurl-http",
			Usage:  "if this flag is set it will always be the base url for http products. Scheme should be excluded, e.g.,: pinned-cdn.mozilla.com/pub",
			EnvVar: "BOUNCER_PINNED_BASEURL_HTTP",
		},
		cli.StringFlag{
			Name:   "pinned-baseurl-https",
			Usage:  "if this flag is set it will always be the base url for https products. Scheme should be excluded, e.g.,: pinned-cdn.mozilla.com/pub",
			EnvVar: "BOUNCER_PINNED_BASEURL_HTTPS",
		},
		cli.StringFlag{
			Name:   "stub-root-url",
			Value:  "",
			Usage:  "Root url of service used to service modified stub installers",
			EnvVar: "STUB_ROOT_URL",
		},
	}
	app.RunAndExitOnError()
}

func Main(c *cli.Context) {
	db, err := bouncer.NewDB(c.String("db-dsn"))
	if err != nil {
		log.Fatalf("Could not open DB: %v", err)
	}
	defer db.Close()

	bouncerHandler := &BouncerHandler{
		db:                 db,
		CacheTime:          time.Duration(c.Int("cache-time")) * time.Second,
		PinnedBaseURLHttp:  c.String("pinned-baseurl-http"),
		PinnedBaseURLHttps: c.String("pinned-baseurl-https"),
		StubRootURL:        c.String("stub-root-url"),
	}

	healthHandler := &HealthHandler{
		db:        db,
		CacheTime: 5 * time.Second,
	}

	mux := http.NewServeMux()

	mux.Handle("/__heartbeat__", healthHandler)
	mux.Handle("/", bouncerHandler)

	server := &http.Server{
		Addr:    c.String("addr"),
		Handler: mux,
	}

	err = server.ListenAndServe()
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>