<commit_before>package main

import (
	"bytes"
	"errors"
	"io/ioutil"
	"log"
	"os"
	"os/user"
	"path"
	"strings"
	"syscall"

	"github.com/codegangsta/cli"
	"github.com/hpcloud/tail"
)

type EdwardConfiguration struct {
	Dir    string
	LogDir string
	PidDir string
}

var EdwardConfig EdwardConfiguration = EdwardConfiguration{}

func createDirIfNeeded(path string) {
	if _, err := os.Stat(path); os.IsNotExist(err) {
		os.MkdirAll(path, 0777)
	}
}

func (e *EdwardConfiguration) initialize() error {
	user, err := user.Current()
	if err != nil {
		return err
	}
	e.Dir = path.Join(user.HomeDir, ".edward")
	e.LogDir = path.Join(e.Dir, "logs")
	e.PidDir = path.Join(e.Dir, "pidFiles")
	createDirIfNeeded(e.Dir)
	createDirIfNeeded(e.LogDir)
	createDirIfNeeded(e.PidDir)
	return nil
}

var groups map[string]*ServiceGroupConfig
var services map[string]*ServiceConfig

func thirdPartyService(name string, startCommand string, stopCommand string, started string) *ServiceConfig {
	pathStr := "$ALPHA"
	return &ServiceConfig{
		Name: name,
		Path: &pathStr,
		Commands: ServiceConfigCommands{
			Launch: startCommand,
			Stop:   stopCommand,
		},
		Properties: ServiceConfigProperties{
			Started: started,
		},
	}
}

func playService(name string) *ServiceConfig {
	pathStr := "$ALPHA"
	return &ServiceConfig{
		Name: name,
		Path: &pathStr,
		Commands: ServiceConfigCommands{
			Build:  "python tools/icbm/build.py :" + name + "_dev",
			Launch: "YEXT_RABBITMQ=localhost thirdparty/play/play test src/com/yext/" + name,
		},
		Properties: ServiceConfigProperties{
			Started: "Server is up and running",
		},
	}
}

func javaService(name string) *ServiceConfig {
	pathStr := "$ALPHA"
	return &ServiceConfig{
		Name: name,
		Path: &pathStr,
		Commands: ServiceConfigCommands{
			Build:  "python tools/icbm/build.py :" + name,
			Launch: "YEXT_RABBITMQ=localhost YEXT_SITE=office JVM_ARGS='-Xmx3G' build/" + name + "/" + name,
		},
		Properties: ServiceConfigProperties{
			Started: "Listening",
		},
	}
}

func goService(name string, goPackage string) *ServiceConfig {
	pathStr := "$ALPHA"
	return &ServiceConfig{
		Name: name,
		Path: &pathStr,
		Commands: ServiceConfigCommands{
			Build:  "go install " + goPackage,
			Launch: "YEXT_RABBITMQ=localhost " + name,
		},
		Properties: ServiceConfigProperties{
			Started: "Listening",
		},
	}
}

func loadConfig() {
	// TODO: Load configuration from the config file and populate the service and groups variables

	groups = make(map[string]*ServiceGroupConfig)
	services = make(map[string]*ServiceConfig)

	services["rabbitmq"] = thirdPartyService("rabbitmq", "sudo rabbitmq-server", "sudo rabbitmqctl stop", "completed")
	// TODO: haproxy actually needs a kill -9 to effectively die
	// TODO: haproxy also doesn't have an effective start output
	services["haproxy"] = thirdPartyService("haproxy", "sudo $ALPHA/tools/bin/haproxy_localhost.sh", "", "backend")

	services["admin2"] = playService("admin2")
	services["users"] = playService("users")
	services["storm"] = playService("storm")
	services["locationsstorm"] = playService("locationsstorm")
	services["ProfileServer"] = javaService("ProfileServer")

	services["sites-staging"] = goService("sites-staging", "yext/pages/sites/sites-staging")
	services["sites-storm"] = goService("sites-storm", "yext/pages/sites/sites-storm")
	services["sites-cog"] = goService("sites-cog", "yext/pages/sites/sites-cog")

	services["resellersapi"] = playService("resellersapi")
	services["subscriptions"] = playService("subscriptions")
	services["SalesApiServer"] = javaService("SalesApiServer")

	groups["thirdparty"] = &ServiceGroupConfig{
		Name: "thirdparty",
		Services: []*ServiceConfig{
			services["rabbitmq"],
			services["haproxy"],
		},
	}

	groups["storm"] = &ServiceGroupConfig{
		Name: "storm",
		Groups: []*ServiceGroupConfig{
			groups["thirdparty"],
		},
		Services: []*ServiceConfig{
			services["admin2"],
			services["users"],
			services["storm"],
			services["locationsstorm"],
			services["ProfileServer"],
		},
	}

	groups["pages"] = &ServiceGroupConfig{
		Name: "pages",
		Groups: []*ServiceGroupConfig{
			groups["storm"],
		},
		Services: []*ServiceConfig{
			services["sites-staging"],
			services["sites-storm"],
			services["sites-cog"],
		},
	}

	groups["resellers"] = &ServiceGroupConfig{
		Name: "resellers",
		Groups: []*ServiceGroupConfig{
			groups["storm"],
		},
		Services: []*ServiceConfig{
			services["resellersapi"],
			services["subscriptions"],
			services["SalesApiServer"],
		},
	}
}

func getServiceOrGroup(name string) (ServiceOrGroup, error) {
	if group, ok := groups[name]; ok {
		return group, nil
	}
	if service, ok := services[name]; ok {
		return service, nil
	}
	return nil, errors.New("Service or group not found")
}

func list(c *cli.Context) {
	println("Services and groups")
	println("Groups:")
	for name, _ := range groups {
		println("\t", name)
	}
	println("Services:")
	for name, _ := range services {
		println("\t", name)
	}
}

func generate(c *cli.Context) {
	println("Generate config")
}

func allStatus() {
	var statuses []ServiceStatus
	for _, service := range services {
		statuses = append(statuses, service.GetStatus()...)
	}
	for _, status := range statuses {
		println(status.Service.Name, ":", status.Status)
	}
}

func status(c *cli.Context) {

	if len(c.Args()) == 0 {
		allStatus()
		return
	}

	name := c.Args()[0]
	s, err := getServiceOrGroup(name)
	if err != nil {
		log.Fatal(err)
	}
	statuses := s.GetStatus()
	for _, status := range statuses {
		println(status.Service.Name, ":", status.Status)
	}
}

func messages(c *cli.Context) {
	log.Fatal("Unimplemented")
}

func start(c *cli.Context) {
	name := c.Args()[0]
	s, err := getServiceOrGroup(name)
	if err != nil {
		log.Fatal(err)
	}
	println("==== Build Phase ====")
	err = s.Build()
	if err != nil {
		log.Fatal("Error building ", name, ": ", err)
	}
	println("==== Launch Phase ====")
	err = s.Start()
	if err != nil {
		log.Fatal("Error launching ", name, ": ", err)
	}
}

func stop(c *cli.Context) {
	name := c.Args()[0]
	s, err := getServiceOrGroup(name)
	if err != nil {
		log.Fatal(err)
	}
	err = s.Stop()
	if err != nil {
		log.Fatal(err)
	}
}

func restart(c *cli.Context) {
	name := c.Args()[0]
	s, err := getServiceOrGroup(name)
	if err != nil {
		log.Fatal(err)
	}
	err = s.Stop()
	if err != nil {
		log.Fatal(err)
	}
	err = s.Build()
	if err != nil {
		log.Fatal(err)
	}
	err = s.Start()
	if err != nil {
		log.Fatal(err)
	}
}

func doLog(c *cli.Context) {
	name := c.Args()[0]
	if _, ok := groups[name]; ok {
		log.Fatal(errors.New("Cannot output group logs"))
	}
	if service, ok := services[name]; ok {
		command := service.GetCommand()
		runLog := command.Logs.Run
		t, err := tail.TailFile(runLog, tail.Config{Follow: true})
		if err != nil {
			log.Fatal(err)
		}
		for line := range t.Lines {
			println(line.Text)
		}
		return
	}
	log.Fatal("Service not found:", name)
}

func checkNotSudo() {
	user, err := user.Current()
	if err != nil {
		log.Fatal(err)
	}
	if user.Uid == "0" {
		log.Fatal("edward should not be run with sudo")
	}
}

func createScriptFile(suffix string, content string) (*os.File, error) {
	file, err := ioutil.TempFile(os.TempDir(), suffix)
	if err != nil {
		return nil, err
	}
	file.WriteString(content)

	err = os.Chmod(file.Name(), 0777)
	if err != nil {
		return nil, err
	}

	return file, nil
}

func ensureSudoAble() {
	var buffer bytes.Buffer

	buffer.WriteString("#!/bin/bash\n")
	buffer.WriteString("sudo echo Test > /dev/null\n")
	buffer.WriteString("ISCHILD=YES ")
	buffer.WriteString(strings.Join(os.Args, " "))
	buffer.WriteString("\n")

	file, err := createScriptFile("sudoAbility", buffer.String())
	if err != nil {
		log.Fatal(err)
	}

	err = syscall.Exec(file.Name(), []string{file.Name()}, os.Environ())
	if err != nil {
		log.Fatal(err)
	}
}

func main() {

	checkNotSudo()

	isChild := os.Getenv("ISCHILD")
	if isChild == "" {
		ensureSudoAble()
		return
	}

	app := cli.NewApp()
	app.Name = "Edward"
	app.Usage = "Manage local microservices"
	app.Before = func(c *cli.Context) error {
		err := EdwardConfig.initialize()
		if err != nil {
			return err
		}
		loadConfig()
		return nil
	}
	app.Commands = []cli.Command{
		{
			Name:   "list",
			Usage:  "List available services",
			Action: list,
		},
		{
			Name:   "generate",
			Usage:  "Generate Edward config for a source tree",
			Action: generate,
		},
		{
			Name:   "status",
			Usage:  "Display service status",
			Action: status,
		},
		{
			Name:   "messages",
			Usage:  "Show messages from services",
			Action: messages,
		},
		{
			Name:   "start",
			Usage:  "Build and launch a service",
			Action: start,
		},
		{
			Name:   "stop",
			Usage:  "Stop a service",
			Action: stop,
		},
		{
			Name:   "restart",
			Usage:  "Rebuild and relaunch a service",
			Action: restart,
		},
		{
			Name:   "log",
			Usage:  "Tail the log for a service",
			Action: doLog,
		},
	}

	app.Run(os.Args)
}
<commit_msg>Don't use sudo for rabbitmq (isn't actually needed and messes up ownership)<commit_after>package main

import (
	"bytes"
	"errors"
	"io/ioutil"
	"log"
	"os"
	"os/user"
	"path"
	"strings"
	"syscall"

	"github.com/codegangsta/cli"
	"github.com/hpcloud/tail"
)

type EdwardConfiguration struct {
	Dir    string
	LogDir string
	PidDir string
}

var EdwardConfig EdwardConfiguration = EdwardConfiguration{}

func createDirIfNeeded(path string) {
	if _, err := os.Stat(path); os.IsNotExist(err) {
		os.MkdirAll(path, 0777)
	}
}

func (e *EdwardConfiguration) initialize() error {
	user, err := user.Current()
	if err != nil {
		return err
	}
	e.Dir = path.Join(user.HomeDir, ".edward")
	e.LogDir = path.Join(e.Dir, "logs")
	e.PidDir = path.Join(e.Dir, "pidFiles")
	createDirIfNeeded(e.Dir)
	createDirIfNeeded(e.LogDir)
	createDirIfNeeded(e.PidDir)
	return nil
}

var groups map[string]*ServiceGroupConfig
var services map[string]*ServiceConfig

func thirdPartyService(name string, startCommand string, stopCommand string, started string) *ServiceConfig {
	pathStr := "$ALPHA"
	return &ServiceConfig{
		Name: name,
		Path: &pathStr,
		Commands: ServiceConfigCommands{
			Launch: startCommand,
			Stop:   stopCommand,
		},
		Properties: ServiceConfigProperties{
			Started: started,
		},
	}
}

func playService(name string) *ServiceConfig {
	pathStr := "$ALPHA"
	return &ServiceConfig{
		Name: name,
		Path: &pathStr,
		Commands: ServiceConfigCommands{
			Build:  "python tools/icbm/build.py :" + name + "_dev",
			Launch: "YEXT_RABBITMQ=localhost thirdparty/play/play test src/com/yext/" + name,
		},
		Properties: ServiceConfigProperties{
			Started: "Server is up and running",
		},
	}
}

func javaService(name string) *ServiceConfig {
	pathStr := "$ALPHA"
	return &ServiceConfig{
		Name: name,
		Path: &pathStr,
		Commands: ServiceConfigCommands{
			Build:  "python tools/icbm/build.py :" + name,
			Launch: "YEXT_RABBITMQ=localhost YEXT_SITE=office JVM_ARGS='-Xmx3G' build/" + name + "/" + name,
		},
		Properties: ServiceConfigProperties{
			Started: "Listening",
		},
	}
}

func goService(name string, goPackage string) *ServiceConfig {
	pathStr := "$ALPHA"
	return &ServiceConfig{
		Name: name,
		Path: &pathStr,
		Commands: ServiceConfigCommands{
			Build:  "go install " + goPackage,
			Launch: "YEXT_RABBITMQ=localhost " + name,
		},
		Properties: ServiceConfigProperties{
			Started: "Listening",
		},
	}
}

func loadConfig() {
	// TODO: Load configuration from the config file and populate the service and groups variables

	groups = make(map[string]*ServiceGroupConfig)
	services = make(map[string]*ServiceConfig)

	services["rabbitmq"] = thirdPartyService("rabbitmq", "rabbitmq-server", "rabbitmqctl stop", "completed")
	// TODO: haproxy actually needs a kill -9 to effectively die
	// TODO: haproxy also doesn't have an effective start output
	services["haproxy"] = thirdPartyService("haproxy", "sudo $ALPHA/tools/bin/haproxy_localhost.sh", "", "backend")

	services["admin2"] = playService("admin2")
	services["users"] = playService("users")
	services["storm"] = playService("storm")
	services["locationsstorm"] = playService("locationsstorm")
	services["ProfileServer"] = javaService("ProfileServer")

	services["sites-staging"] = goService("sites-staging", "yext/pages/sites/sites-staging")
	services["sites-storm"] = goService("sites-storm", "yext/pages/sites/sites-storm")
	services["sites-cog"] = goService("sites-cog", "yext/pages/sites/sites-cog")

	services["resellersapi"] = playService("resellersapi")
	services["subscriptions"] = playService("subscriptions")
	services["SalesApiServer"] = javaService("SalesApiServer")

	groups["thirdparty"] = &ServiceGroupConfig{
		Name: "thirdparty",
		Services: []*ServiceConfig{
			services["rabbitmq"],
			services["haproxy"],
		},
	}

	groups["storm"] = &ServiceGroupConfig{
		Name: "storm",
		Groups: []*ServiceGroupConfig{
			groups["thirdparty"],
		},
		Services: []*ServiceConfig{
			services["admin2"],
			services["users"],
			services["storm"],
			services["locationsstorm"],
			services["ProfileServer"],
		},
	}

	groups["pages"] = &ServiceGroupConfig{
		Name: "pages",
		Groups: []*ServiceGroupConfig{
			groups["storm"],
		},
		Services: []*ServiceConfig{
			services["sites-staging"],
			services["sites-storm"],
			services["sites-cog"],
		},
	}

	groups["resellers"] = &ServiceGroupConfig{
		Name: "resellers",
		Groups: []*ServiceGroupConfig{
			groups["storm"],
		},
		Services: []*ServiceConfig{
			services["resellersapi"],
			services["subscriptions"],
			services["SalesApiServer"],
		},
	}
}

func getServiceOrGroup(name string) (ServiceOrGroup, error) {
	if group, ok := groups[name]; ok {
		return group, nil
	}
	if service, ok := services[name]; ok {
		return service, nil
	}
	return nil, errors.New("Service or group not found")
}

func list(c *cli.Context) {
	println("Services and groups")
	println("Groups:")
	for name, _ := range groups {
		println("\t", name)
	}
	println("Services:")
	for name, _ := range services {
		println("\t", name)
	}
}

func generate(c *cli.Context) {
	println("Generate config")
}

func allStatus() {
	var statuses []ServiceStatus
	for _, service := range services {
		statuses = append(statuses, service.GetStatus()...)
	}
	for _, status := range statuses {
		println(status.Service.Name, ":", status.Status)
	}
}

func status(c *cli.Context) {

	if len(c.Args()) == 0 {
		allStatus()
		return
	}

	name := c.Args()[0]
	s, err := getServiceOrGroup(name)
	if err != nil {
		log.Fatal(err)
	}
	statuses := s.GetStatus()
	for _, status := range statuses {
		println(status.Service.Name, ":", status.Status)
	}
}

func messages(c *cli.Context) {
	log.Fatal("Unimplemented")
}

func start(c *cli.Context) {
	name := c.Args()[0]
	s, err := getServiceOrGroup(name)
	if err != nil {
		log.Fatal(err)
	}
	println("==== Build Phase ====")
	err = s.Build()
	if err != nil {
		log.Fatal("Error building ", name, ": ", err)
	}
	println("==== Launch Phase ====")
	err = s.Start()
	if err != nil {
		log.Fatal("Error launching ", name, ": ", err)
	}
}

func stop(c *cli.Context) {
	name := c.Args()[0]
	s, err := getServiceOrGroup(name)
	if err != nil {
		log.Fatal(err)
	}
	err = s.Stop()
	if err != nil {
		log.Fatal(err)
	}
}

func restart(c *cli.Context) {
	name := c.Args()[0]
	s, err := getServiceOrGroup(name)
	if err != nil {
		log.Fatal(err)
	}
	err = s.Stop()
	if err != nil {
		log.Fatal(err)
	}
	err = s.Build()
	if err != nil {
		log.Fatal(err)
	}
	err = s.Start()
	if err != nil {
		log.Fatal(err)
	}
}

func doLog(c *cli.Context) {
	name := c.Args()[0]
	if _, ok := groups[name]; ok {
		log.Fatal(errors.New("Cannot output group logs"))
	}
	if service, ok := services[name]; ok {
		command := service.GetCommand()
		runLog := command.Logs.Run
		t, err := tail.TailFile(runLog, tail.Config{Follow: true})
		if err != nil {
			log.Fatal(err)
		}
		for line := range t.Lines {
			println(line.Text)
		}
		return
	}
	log.Fatal("Service not found:", name)
}

func checkNotSudo() {
	user, err := user.Current()
	if err != nil {
		log.Fatal(err)
	}
	if user.Uid == "0" {
		log.Fatal("edward should not be run with sudo")
	}
}

func createScriptFile(suffix string, content string) (*os.File, error) {
	file, err := ioutil.TempFile(os.TempDir(), suffix)
	if err != nil {
		return nil, err
	}
	file.WriteString(content)

	err = os.Chmod(file.Name(), 0777)
	if err != nil {
		return nil, err
	}

	return file, nil
}

func ensureSudoAble() {
	var buffer bytes.Buffer

	buffer.WriteString("#!/bin/bash\n")
	buffer.WriteString("sudo echo Test > /dev/null\n")
	buffer.WriteString("ISCHILD=YES ")
	buffer.WriteString(strings.Join(os.Args, " "))
	buffer.WriteString("\n")

	file, err := createScriptFile("sudoAbility", buffer.String())
	if err != nil {
		log.Fatal(err)
	}

	err = syscall.Exec(file.Name(), []string{file.Name()}, os.Environ())
	if err != nil {
		log.Fatal(err)
	}
}

func main() {

	checkNotSudo()

	isChild := os.Getenv("ISCHILD")
	if isChild == "" {
		ensureSudoAble()
		return
	}

	app := cli.NewApp()
	app.Name = "Edward"
	app.Usage = "Manage local microservices"
	app.Before = func(c *cli.Context) error {
		err := EdwardConfig.initialize()
		if err != nil {
			return err
		}
		loadConfig()
		return nil
	}
	app.Commands = []cli.Command{
		{
			Name:   "list",
			Usage:  "List available services",
			Action: list,
		},
		{
			Name:   "generate",
			Usage:  "Generate Edward config for a source tree",
			Action: generate,
		},
		{
			Name:   "status",
			Usage:  "Display service status",
			Action: status,
		},
		{
			Name:   "messages",
			Usage:  "Show messages from services",
			Action: messages,
		},
		{
			Name:   "start",
			Usage:  "Build and launch a service",
			Action: start,
		},
		{
			Name:   "stop",
			Usage:  "Stop a service",
			Action: stop,
		},
		{
			Name:   "restart",
			Usage:  "Rebuild and relaunch a service",
			Action: restart,
		},
		{
			Name:   "log",
			Usage:  "Tail the log for a service",
			Action: doLog,
		},
	}

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


<commit_before>package main

import (
	"flag"
	"fmt"
	"net/http"
	"os"
	"os/user"
	"time"

	"golang.org/x/net/context"

	"golang.org/x/oauth2"

	"github.com/jinzhu/gorm"
	_ "github.com/lib/pq"

	logrus "github.com/Sirupsen/logrus"
	"github.com/almighty/almighty-core/account"
	"github.com/almighty/almighty-core/app"
	"github.com/almighty/almighty-core/configuration"
	"github.com/almighty/almighty-core/gormapplication"
	"github.com/almighty/almighty-core/jsonapi"
	"github.com/almighty/almighty-core/log"
	"github.com/almighty/almighty-core/login"
	"github.com/almighty/almighty-core/migration"
	"github.com/almighty/almighty-core/models"
	"github.com/almighty/almighty-core/remoteworkitem"
	"github.com/almighty/almighty-core/token"
	"github.com/almighty/almighty-core/workitem"
	"github.com/almighty/almighty-core/workitem/link"

	"github.com/goadesign/goa"
	"github.com/goadesign/goa/client"
	goalogrus "github.com/goadesign/goa/logging/logrus"
	"github.com/goadesign/goa/middleware"
	"github.com/goadesign/goa/middleware/gzip"
	"github.com/goadesign/goa/middleware/security/jwt"
)

var (
	// Commit current build commit set by build script
	Commit = "0"
	// BuildTime set by build script in ISO 8601 (UTC) format: YYYY-MM-DDThh:mm:ssTZD (see https://www.w3.org/TR/NOTE-datetime for details)
	BuildTime = "0"
	// StartTime in ISO 8601 (UTC) format
	StartTime = time.Now().UTC().Format("2006-01-02T15:04:05Z")
)

func main() {
	// --------------------------------------------------------------------
	// Parse flags
	// --------------------------------------------------------------------
	var configFilePath string
	var printConfig bool
	var migrateDB bool
	var scheduler *remoteworkitem.Scheduler
	flag.StringVar(&configFilePath, "config", "", "Path to the config file to read")
	flag.BoolVar(&printConfig, "printConfig", false, "Prints the config (including merged environment variables) and exits")
	flag.BoolVar(&migrateDB, "migrateDatabase", false, "Migrates the database to the newest version and exits.")
	flag.Parse()

	// Override default -config switch with environment variable only if -config switch was
	// not explicitly given via the command line.
	configSwitchIsSet := false
	flag.Visit(func(f *flag.Flag) {
		if f.Name == "config" {
			configSwitchIsSet = true
		}
	})
	if !configSwitchIsSet {
		if envConfigPath, ok := os.LookupEnv("ALMIGHTY_CONFIG_FILE_PATH"); ok {
			configFilePath = envConfigPath
		}
	}

	var err error
	if err = configuration.Setup(configFilePath); err != nil {
		logrus.Panic(nil, map[string]interface{}{
			"configFilePath": configFilePath,
			"err":            err,
		}, "failed to setup the configuration")
	}

	if printConfig {
		os.Exit(0)
	}

	// Initialized developer mode flag for the logger
	log.InitializeLogger(configuration.IsPostgresDeveloperModeEnabled())

	printUserInfo()

	var db *gorm.DB
	for {
		db, err = gorm.Open("postgres", configuration.GetPostgresConfigString())
		if err != nil {
			db.Close()
			log.Logger().Errorf("ERROR: Unable to open connection to database %v\n", err)
			log.Logger().Infof("Retrying to connect in %v...\n", configuration.GetPostgresConnectionRetrySleep())
			time.Sleep(configuration.GetPostgresConnectionRetrySleep())
		} else {
			defer db.Close()
			break
		}
	}

	if configuration.IsPostgresDeveloperModeEnabled() {
		db = db.Debug()
	}

	// Migrate the schema
	err = migration.Migrate(db.DB())
	if err != nil {
		log.Panic(nil, map[string]interface{}{
			"err": fmt.Sprintf("%+v", err),
		}, "failed migration")
	}

	// Nothing to here except exit, since the migration is already performed.
	if migrateDB {
		os.Exit(0)
	}

	// Make sure the database is populated with the correct types (e.g. bug etc.)
	if configuration.GetPopulateCommonTypes() {
		// set a random request ID for the context
		ctx, req_id := client.ContextWithRequestID(context.Background())
		log.Debug(ctx, nil, "Initializing the population of the database... Request ID: %v", req_id)

		if err := models.Transactional(db, func(tx *gorm.DB) error {
			return migration.PopulateCommonTypes(ctx, tx, workitem.NewWorkItemTypeRepository(tx))
		}); err != nil {
			log.Panic(ctx, map[string]interface{}{
				"err": fmt.Sprintf("%+v", err),
			}, "failed to populate common types")
		}
		if err := models.Transactional(db, func(tx *gorm.DB) error {
			return migration.BootstrapWorkItemLinking(ctx, link.NewWorkItemLinkCategoryRepository(tx), link.NewWorkItemLinkTypeRepository(tx))
		}); err != nil {
			log.Panic(ctx, map[string]interface{}{
				"err": fmt.Sprintf("%+v", err),
			}, "failed to bootstap work item linking")
		}
	}

	// Scheduler to fetch and import remote tracker items
	scheduler = remoteworkitem.NewScheduler(db)
	defer scheduler.Stop()
	scheduler.ScheduleAllQueries()

	// Create service
	service := goa.New("alm")

	// Mount middleware
	service.Use(middleware.RequestID())
	service.Use(middleware.LogRequest(configuration.IsPostgresDeveloperModeEnabled()))
	service.Use(gzip.Middleware(9))
	service.Use(jsonapi.ErrorHandler(service, true))
	service.Use(middleware.Recover())

	service.WithLogger(goalogrus.New(log.Logger()))

	publicKey, err := token.ParsePublicKey(configuration.GetTokenPublicKey())
	if err != nil {
		log.Panic(nil, map[string]interface{}{
			"err": fmt.Sprintf("%+v", err),
		}, "failed to parse public token")
	}

	// Setup Account/Login/Security
	identityRepository := account.NewIdentityRepository(db)
	userRepository := account.NewUserRepository(db)

	tokenManager := token.NewManager(publicKey)
	app.UseJWTMiddleware(service, jwt.New(publicKey, nil, app.NewJWTSecurity()))
	service.Use(login.InjectTokenManager(tokenManager))

	// Mount "login" controller
	oauth := &oauth2.Config{
		ClientID:     configuration.GetKeycloakClientID(),
		ClientSecret: configuration.GetKeycloakSecret(),
		Scopes:       []string{"user:email"},
		Endpoint: oauth2.Endpoint{
			AuthURL:  configuration.GetKeycloakEndpointAuth(),
			TokenURL: configuration.GetKeycloakEndpointToken(),
		},
	}

	appDB := gormapplication.NewGormDB(db)

	loginService := login.NewKeycloakOAuthProvider(oauth, identityRepository, userRepository, tokenManager, appDB)
	loginCtrl := NewLoginController(service, loginService, tokenManager)
	app.MountLoginController(service, loginCtrl)

	// Mount "status" controller
	statusCtrl := NewStatusController(service, db)
	app.MountStatusController(service, statusCtrl)

	// Mount "workitem" controller
	workitemCtrl := NewWorkitemController(service, appDB)
	app.MountWorkitemController(service, workitemCtrl)

	// Mount "workitemtype" controller
	workitemtypeCtrl := NewWorkitemtypeController(service, appDB)
	app.MountWorkitemtypeController(service, workitemtypeCtrl)

	// Mount "work item link category" controller
	workItemLinkCategoryCtrl := NewWorkItemLinkCategoryController(service, appDB)
	app.MountWorkItemLinkCategoryController(service, workItemLinkCategoryCtrl)

	// Mount "work item link type" controller
	workItemLinkTypeCtrl := NewWorkItemLinkTypeController(service, appDB)
	app.MountWorkItemLinkTypeController(service, workItemLinkTypeCtrl)

	// Mount "work item link" controller
	workItemLinkCtrl := NewWorkItemLinkController(service, appDB)
	app.MountWorkItemLinkController(service, workItemLinkCtrl)

	// Mount "work item comments" controller
	workItemCommentsCtrl := NewWorkItemCommentsController(service, appDB)
	app.MountWorkItemCommentsController(service, workItemCommentsCtrl)

	// Mount "work item relationships links" controller
	workItemRelationshipsLinksCtrl := NewWorkItemRelationshipsLinksController(service, appDB)
	app.MountWorkItemRelationshipsLinksController(service, workItemRelationshipsLinksCtrl)

	// Mount "comments" controller
	commentsCtrl := NewCommentsController(service, appDB)
	app.MountCommentsController(service, commentsCtrl)

	// Mount "tracker" controller
	c5 := NewTrackerController(service, appDB, scheduler)
	app.MountTrackerController(service, c5)

	// Mount "trackerquery" controller
	c6 := NewTrackerqueryController(service, appDB, scheduler)
	app.MountTrackerqueryController(service, c6)

	// Mount "space" controller
	spaceCtrl := NewSpaceController(service, appDB)
	app.MountSpaceController(service, spaceCtrl)

	// Mount "user" controller
	userCtrl := NewUserController(service, appDB, tokenManager)
	app.MountUserController(service, userCtrl)

	// Mount "search" controller
	searchCtrl := NewSearchController(service, appDB)
	app.MountSearchController(service, searchCtrl)

	// Mount "indentity" controller
	identityCtrl := NewIdentityController(service, appDB)
	app.MountIdentityController(service, identityCtrl)

	// Mount "users" controller
	usersCtrl := NewUsersController(service, appDB)
	app.MountUsersController(service, usersCtrl)

	// Mount "iterations" controller
	iterationCtrl := NewIterationController(service, appDB)
	app.MountIterationController(service, iterationCtrl)

	// Mount "spaceiterations" controller
	spaceIterationCtrl := NewSpaceIterationsController(service, appDB)
	app.MountSpaceIterationsController(service, spaceIterationCtrl)

	// Mount "userspace" controller
	userspaceCtrl := NewUserspaceController(service, db)
	app.MountUserspaceController(service, userspaceCtrl)

	// Mount "render" controller
	renderCtrl := NewRenderController(service)
	app.MountRenderController(service, renderCtrl)

	// Mount "areas" controller
	areaCtrl := NewAreaController(service, appDB)
	app.MountAreaController(service, areaCtrl)

	spaceAreaCtrl := NewSpaceAreasController(service, appDB)
	app.MountSpaceAreasController(service, spaceAreaCtrl)

	log.Logger().Infoln("Git Commit SHA: ", Commit)
	log.Logger().Infoln("UTC Build Time: ", BuildTime)
	log.Logger().Infoln("UTC Start Time: ", StartTime)
	log.Logger().Infoln("Dev mode:       ", configuration.IsPostgresDeveloperModeEnabled())

	http.Handle("/api/", service.Mux)
	http.Handle("/", http.FileServer(assetFS()))
	http.Handle("/favicon.ico", http.NotFoundHandler())

	// Start http
	if err := http.ListenAndServe(configuration.GetHTTPAddress(), nil); err != nil {
		log.Error(nil, map[string]interface{}{
			"addr": configuration.GetHTTPAddress(),
			"err":  err,
		}, "unable to connect to server")
		service.LogError("startup", "err", err)
	}

}

func printUserInfo() {
	u, err := user.Current()
	if err != nil {
		log.Warn(nil, map[string]interface{}{
			"err": fmt.Sprintf("%+v", err),
		}, "failed to get current user")
	} else {
		log.Info(nil, map[string]interface{}{
			"username": u.Username,
			"uuid":     u.Uid,
		}, "Running as user name '%s' with UID %s.", u.Username, u.Uid)
		/*
			g, err := user.LookupGroupId(u.Gid)
			if err != nil {
				fmt.Printf("Failed to lookup group: %", err.Error())
			} else {
				fmt.Printf("Running with group \"%s\" with GID %s.\n", g.Name, g.Gid)
			}
		*/
	}
}
<commit_msg>Removed unnecessary newlines (#811)<commit_after>package main

import (
	"flag"
	"fmt"
	"net/http"
	"os"
	"os/user"
	"time"

	"golang.org/x/net/context"

	"golang.org/x/oauth2"

	"github.com/jinzhu/gorm"
	_ "github.com/lib/pq"

	logrus "github.com/Sirupsen/logrus"
	"github.com/almighty/almighty-core/account"
	"github.com/almighty/almighty-core/app"
	"github.com/almighty/almighty-core/configuration"
	"github.com/almighty/almighty-core/gormapplication"
	"github.com/almighty/almighty-core/jsonapi"
	"github.com/almighty/almighty-core/log"
	"github.com/almighty/almighty-core/login"
	"github.com/almighty/almighty-core/migration"
	"github.com/almighty/almighty-core/models"
	"github.com/almighty/almighty-core/remoteworkitem"
	"github.com/almighty/almighty-core/token"
	"github.com/almighty/almighty-core/workitem"
	"github.com/almighty/almighty-core/workitem/link"

	"github.com/goadesign/goa"
	"github.com/goadesign/goa/client"
	goalogrus "github.com/goadesign/goa/logging/logrus"
	"github.com/goadesign/goa/middleware"
	"github.com/goadesign/goa/middleware/gzip"
	"github.com/goadesign/goa/middleware/security/jwt"
)

var (
	// Commit current build commit set by build script
	Commit = "0"
	// BuildTime set by build script in ISO 8601 (UTC) format: YYYY-MM-DDThh:mm:ssTZD (see https://www.w3.org/TR/NOTE-datetime for details)
	BuildTime = "0"
	// StartTime in ISO 8601 (UTC) format
	StartTime = time.Now().UTC().Format("2006-01-02T15:04:05Z")
)

func main() {
	// --------------------------------------------------------------------
	// Parse flags
	// --------------------------------------------------------------------
	var configFilePath string
	var printConfig bool
	var migrateDB bool
	var scheduler *remoteworkitem.Scheduler
	flag.StringVar(&configFilePath, "config", "", "Path to the config file to read")
	flag.BoolVar(&printConfig, "printConfig", false, "Prints the config (including merged environment variables) and exits")
	flag.BoolVar(&migrateDB, "migrateDatabase", false, "Migrates the database to the newest version and exits.")
	flag.Parse()

	// Override default -config switch with environment variable only if -config switch was
	// not explicitly given via the command line.
	configSwitchIsSet := false
	flag.Visit(func(f *flag.Flag) {
		if f.Name == "config" {
			configSwitchIsSet = true
		}
	})
	if !configSwitchIsSet {
		if envConfigPath, ok := os.LookupEnv("ALMIGHTY_CONFIG_FILE_PATH"); ok {
			configFilePath = envConfigPath
		}
	}

	var err error
	if err = configuration.Setup(configFilePath); err != nil {
		logrus.Panic(nil, map[string]interface{}{
			"configFilePath": configFilePath,
			"err":            err,
		}, "failed to setup the configuration")
	}

	if printConfig {
		os.Exit(0)
	}

	// Initialized developer mode flag for the logger
	log.InitializeLogger(configuration.IsPostgresDeveloperModeEnabled())

	printUserInfo()

	var db *gorm.DB
	for {
		db, err = gorm.Open("postgres", configuration.GetPostgresConfigString())
		if err != nil {
			db.Close()
			log.Logger().Errorf("ERROR: Unable to open connection to database %v", err)
			log.Logger().Infof("Retrying to connect in %v...", configuration.GetPostgresConnectionRetrySleep())
			time.Sleep(configuration.GetPostgresConnectionRetrySleep())
		} else {
			defer db.Close()
			break
		}
	}

	if configuration.IsPostgresDeveloperModeEnabled() {
		db = db.Debug()
	}

	// Migrate the schema
	err = migration.Migrate(db.DB())
	if err != nil {
		log.Panic(nil, map[string]interface{}{
			"err": fmt.Sprintf("%+v", err),
		}, "failed migration")
	}

	// Nothing to here except exit, since the migration is already performed.
	if migrateDB {
		os.Exit(0)
	}

	// Make sure the database is populated with the correct types (e.g. bug etc.)
	if configuration.GetPopulateCommonTypes() {
		// set a random request ID for the context
		ctx, req_id := client.ContextWithRequestID(context.Background())
		log.Debug(ctx, nil, "Initializing the population of the database... Request ID: %v", req_id)

		if err := models.Transactional(db, func(tx *gorm.DB) error {
			return migration.PopulateCommonTypes(ctx, tx, workitem.NewWorkItemTypeRepository(tx))
		}); err != nil {
			log.Panic(ctx, map[string]interface{}{
				"err": fmt.Sprintf("%+v", err),
			}, "failed to populate common types")
		}
		if err := models.Transactional(db, func(tx *gorm.DB) error {
			return migration.BootstrapWorkItemLinking(ctx, link.NewWorkItemLinkCategoryRepository(tx), link.NewWorkItemLinkTypeRepository(tx))
		}); err != nil {
			log.Panic(ctx, map[string]interface{}{
				"err": fmt.Sprintf("%+v", err),
			}, "failed to bootstap work item linking")
		}
	}

	// Scheduler to fetch and import remote tracker items
	scheduler = remoteworkitem.NewScheduler(db)
	defer scheduler.Stop()
	scheduler.ScheduleAllQueries()

	// Create service
	service := goa.New("alm")

	// Mount middleware
	service.Use(middleware.RequestID())
	service.Use(middleware.LogRequest(configuration.IsPostgresDeveloperModeEnabled()))
	service.Use(gzip.Middleware(9))
	service.Use(jsonapi.ErrorHandler(service, true))
	service.Use(middleware.Recover())

	service.WithLogger(goalogrus.New(log.Logger()))

	publicKey, err := token.ParsePublicKey(configuration.GetTokenPublicKey())
	if err != nil {
		log.Panic(nil, map[string]interface{}{
			"err": fmt.Sprintf("%+v", err),
		}, "failed to parse public token")
	}

	// Setup Account/Login/Security
	identityRepository := account.NewIdentityRepository(db)
	userRepository := account.NewUserRepository(db)

	tokenManager := token.NewManager(publicKey)
	app.UseJWTMiddleware(service, jwt.New(publicKey, nil, app.NewJWTSecurity()))
	service.Use(login.InjectTokenManager(tokenManager))

	// Mount "login" controller
	oauth := &oauth2.Config{
		ClientID:     configuration.GetKeycloakClientID(),
		ClientSecret: configuration.GetKeycloakSecret(),
		Scopes:       []string{"user:email"},
		Endpoint: oauth2.Endpoint{
			AuthURL:  configuration.GetKeycloakEndpointAuth(),
			TokenURL: configuration.GetKeycloakEndpointToken(),
		},
	}

	appDB := gormapplication.NewGormDB(db)

	loginService := login.NewKeycloakOAuthProvider(oauth, identityRepository, userRepository, tokenManager, appDB)
	loginCtrl := NewLoginController(service, loginService, tokenManager)
	app.MountLoginController(service, loginCtrl)

	// Mount "status" controller
	statusCtrl := NewStatusController(service, db)
	app.MountStatusController(service, statusCtrl)

	// Mount "workitem" controller
	workitemCtrl := NewWorkitemController(service, appDB)
	app.MountWorkitemController(service, workitemCtrl)

	// Mount "workitemtype" controller
	workitemtypeCtrl := NewWorkitemtypeController(service, appDB)
	app.MountWorkitemtypeController(service, workitemtypeCtrl)

	// Mount "work item link category" controller
	workItemLinkCategoryCtrl := NewWorkItemLinkCategoryController(service, appDB)
	app.MountWorkItemLinkCategoryController(service, workItemLinkCategoryCtrl)

	// Mount "work item link type" controller
	workItemLinkTypeCtrl := NewWorkItemLinkTypeController(service, appDB)
	app.MountWorkItemLinkTypeController(service, workItemLinkTypeCtrl)

	// Mount "work item link" controller
	workItemLinkCtrl := NewWorkItemLinkController(service, appDB)
	app.MountWorkItemLinkController(service, workItemLinkCtrl)

	// Mount "work item comments" controller
	workItemCommentsCtrl := NewWorkItemCommentsController(service, appDB)
	app.MountWorkItemCommentsController(service, workItemCommentsCtrl)

	// Mount "work item relationships links" controller
	workItemRelationshipsLinksCtrl := NewWorkItemRelationshipsLinksController(service, appDB)
	app.MountWorkItemRelationshipsLinksController(service, workItemRelationshipsLinksCtrl)

	// Mount "comments" controller
	commentsCtrl := NewCommentsController(service, appDB)
	app.MountCommentsController(service, commentsCtrl)

	// Mount "tracker" controller
	c5 := NewTrackerController(service, appDB, scheduler)
	app.MountTrackerController(service, c5)

	// Mount "trackerquery" controller
	c6 := NewTrackerqueryController(service, appDB, scheduler)
	app.MountTrackerqueryController(service, c6)

	// Mount "space" controller
	spaceCtrl := NewSpaceController(service, appDB)
	app.MountSpaceController(service, spaceCtrl)

	// Mount "user" controller
	userCtrl := NewUserController(service, appDB, tokenManager)
	app.MountUserController(service, userCtrl)

	// Mount "search" controller
	searchCtrl := NewSearchController(service, appDB)
	app.MountSearchController(service, searchCtrl)

	// Mount "indentity" controller
	identityCtrl := NewIdentityController(service, appDB)
	app.MountIdentityController(service, identityCtrl)

	// Mount "users" controller
	usersCtrl := NewUsersController(service, appDB)
	app.MountUsersController(service, usersCtrl)

	// Mount "iterations" controller
	iterationCtrl := NewIterationController(service, appDB)
	app.MountIterationController(service, iterationCtrl)

	// Mount "spaceiterations" controller
	spaceIterationCtrl := NewSpaceIterationsController(service, appDB)
	app.MountSpaceIterationsController(service, spaceIterationCtrl)

	// Mount "userspace" controller
	userspaceCtrl := NewUserspaceController(service, db)
	app.MountUserspaceController(service, userspaceCtrl)

	// Mount "render" controller
	renderCtrl := NewRenderController(service)
	app.MountRenderController(service, renderCtrl)

	// Mount "areas" controller
	areaCtrl := NewAreaController(service, appDB)
	app.MountAreaController(service, areaCtrl)

	spaceAreaCtrl := NewSpaceAreasController(service, appDB)
	app.MountSpaceAreasController(service, spaceAreaCtrl)

	log.Logger().Infoln("Git Commit SHA: ", Commit)
	log.Logger().Infoln("UTC Build Time: ", BuildTime)
	log.Logger().Infoln("UTC Start Time: ", StartTime)
	log.Logger().Infoln("Dev mode:       ", configuration.IsPostgresDeveloperModeEnabled())

	http.Handle("/api/", service.Mux)
	http.Handle("/", http.FileServer(assetFS()))
	http.Handle("/favicon.ico", http.NotFoundHandler())

	// Start http
	if err := http.ListenAndServe(configuration.GetHTTPAddress(), nil); err != nil {
		log.Error(nil, map[string]interface{}{
			"addr": configuration.GetHTTPAddress(),
			"err":  err,
		}, "unable to connect to server")
		service.LogError("startup", "err", err)
	}

}

func printUserInfo() {
	u, err := user.Current()
	if err != nil {
		log.Warn(nil, map[string]interface{}{
			"err": fmt.Sprintf("%+v", err),
		}, "failed to get current user")
	} else {
		log.Info(nil, map[string]interface{}{
			"username": u.Username,
			"uuid":     u.Uid,
		}, "Running as user name '%s' with UID %s.", u.Username, u.Uid)
		/*
			g, err := user.LookupGroupId(u.Gid)
			if err != nil {
				fmt.Printf("Failed to lookup group: %", err.Error())
			} else {
				fmt.Printf("Running with group \"%s\" with GID %s.\n", g.Name, g.Gid)
			}
		*/
	}
}
<|endoftext|>


<commit_before>package main

import (
	"archive/tar"
	"compress/gzip"
	"fmt"
	"io"
	"log"
	"os"
	"path"
	"strings"

	"github.com/kr/fs"
)

var (
	fileNamesToPack   = []string{"readme", "license"}
	allowedExtensions = []string{"", ".txt", ".md"}
)

func main() {
	if len(os.Args) == 0 {
		log.Fatalln("nothing to tar")
	}
	if err := tarball(os.Args[1:]...); err != nil {
		log.Fatal(err)
	}
}

func tarball(filepaths ...string) error {
	for _, fpath := range filepaths {

		// print for users
		fmt.Println(fpath + ".tar.gz")

		// set up the output file
		file, err := os.Create(fpath + ".tar.gz")
		if err != nil {
			return err
		}
		defer file.Close()

		// set up the gzip writer
		gw := gzip.NewWriter(file)
		defer gw.Close()
		tw := tar.NewWriter(gw)
		defer tw.Close()

		filepaths := []string{fpath}

		w := fs.Walk(".")
		w.Step()
		for w.Step() {

			fstat := w.Stat()
			if fstat.IsDir() {
				w.SkipDir()
				continue
			}
			if w.Err() != nil {
				return w.Err()
			}

			fname := fstat.Name()
			ext := path.Ext(fname)
			for _, allowed := range allowedExtensions {
				if ext == allowed {
					for _, fileToPack := range fileNamesToPack {
						fnameWithoutExt := fname[:len(fstat.Name())-len(ext)]
						if strings.ToLower(fnameWithoutExt) == fileToPack {
							filepaths = append(filepaths, fname)
							break
						}
					}
					break
				}
			}
		}

		for _, fpath := range filepaths {
			if err := addFile(tw, fpath); err != nil {
				log.Fatalln(err)
			}
		}
	}
	return nil
}

func addFile(tw *tar.Writer, path string) error {

	file, err := os.Open(path)
	if err != nil {
		return err
	}
	defer file.Close()

	if stat, err := file.Stat(); err == nil {

		// now lets create the header as needed for this file within the tarball
		header, err := tar.FileInfoHeader(stat, stat.Name())
		if err != nil {
			return err
		}

		// write the header to the tarball archive
		if err := tw.WriteHeader(header); err != nil {
			return err
		}

		// copy the file data to the tarball
		if _, err := io.Copy(tw, file); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>add gox default naming support<commit_after>package main

import (
	"archive/tar"
	"compress/gzip"
	"fmt"
	"io"
	"log"
	"os"
	"path"
	"strings"

	"github.com/kr/fs"
)

var (
	fileNamesToPack   = []string{"readme", "license"}
	allowedExtensions = []string{"", ".txt", ".md"}
	osList            = []string{"darwin", "freebsd", "linux", "netbsd", "openbsd", "windows"}
	archList          = []string{"386", "386.exe", "amd64", "amd64.exe", "arm"}
)

func main() {
	if len(os.Args) == 0 {
		log.Fatalln("nothing to tar")
	}
	if err := tarball(os.Args[1:]...); err != nil {
		log.Fatal(err)
	}
}

func tarball(filepaths ...string) error {
	for _, fpath := range filepaths {

		// print for users
		fmt.Println(fpath + ".tar.gz")

		// set up the output file
		file, err := os.Create(fpath + ".tar.gz")
		if err != nil {
			return err
		}
		defer file.Close()

		// set up the gzip writer
		gw := gzip.NewWriter(file)
		defer gw.Close()
		tw := tar.NewWriter(gw)
		defer tw.Close()

		filepaths := []string{fpath}
		w := fs.Walk(".")
		w.Step()
		for w.Step() {

			fstat := w.Stat()
			if fstat.IsDir() {
				w.SkipDir()
				continue
			}
			if w.Err() != nil {
				return w.Err()
			}

			fname := fstat.Name()
			ext := path.Ext(fname)
			for _, allowed := range allowedExtensions {
				if ext == allowed {
					for _, fileToPack := range fileNamesToPack {
						fnameWithoutExt := fname[:len(fstat.Name())-len(ext)]
						if strings.ToLower(fnameWithoutExt) == fileToPack {
							filepaths = append(filepaths, fname)
							break
						}
					}
					break
				}
			}
		}

		for _, fpath := range filepaths {
			if err := addFile(tw, fpath); err != nil {
				log.Fatalln(err)
			}
		}
	}
	return nil
}

func addFile(tw *tar.Writer, path string) error {

	// open a file, we will close it manually later
	file, err := os.Open(path)
	if err != nil {
		return err
	}

	// get info on that file
	finfo, err := file.Stat()
	if err != nil {
		return err
	}

	// default the name of the file to its current name
	name := finfo.Name()

	// if the name of the file contains two "_" we can assume it is probably a
	// default gox naming template convention of "{{.Dir}}_{{.OS}}_{{.Arch}}".
	if nameslice := strings.Split(name, "_"); len(nameslice) == 3 {

		// check the os name value is valid
		for _, osname := range osList {
			if nameslice[1] == osname {
				name = nameslice[0]
				break
			}
		}

		// check the arch name value is valid
		for i, arch := range archList {
			if nameslice[2] == arch {
				break
			}
			// if this is the last value in the slice, it means we have not matched
			// any arch values, and maybe not os values, therefore default back to
			// the original file name
			if i == len(osList)-1 {
				name = finfo.Name()
			}
		}

		// if the name has changed, we will need to update file info
		if name != finfo.Name() {

			// first rename the binary to its normal name
			if err := os.Rename(finfo.Name(), name); err != nil {
				return err
			}

			// close the file
			file.Close()

			// open the renamed file
			file, err = os.Open(name)
			if err != nil {
				return err
			}

			// update the file info
			if finfo, err = file.Stat(); err != nil {
				return err
			}
		}

		// now lets create the header as needed for this file within the tarball
		header, err := tar.FileInfoHeader(finfo, finfo.Name())
		if err != nil {
			return err
		}

		// write the header to the tarball archive
		if err := tw.WriteHeader(header); err != nil {
			return err
		}

		// copy the file data to the tarball
		if _, err := io.Copy(tw, file); err != nil {
			return err
		}

		// remove the binary since we may have renamed it
		if err := os.Remove(finfo.Name()); err != nil {
			return err
		}
	}

	// close the file
	file.Close()
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"os"
	"path"

	docopt "github.com/docopt/docopt-go"
	"github.com/goggle/flatten/filesystem"
	"github.com/goggle/flatten/flatten"
	"github.com/goggle/flatten/osabstraction"
)

const version = "0.8"

func ask(question string, defaultYes bool) bool {
	var defaultString string
	if defaultYes {
		defaultString = "[y]/n:"
	} else {
		defaultString = "y/[n]:"
	}
	reader := bufio.NewReader(os.Stdin)
	fmt.Printf(question + " " + defaultString + " ")
	test, _ := reader.ReadString('\n')
	if defaultYes {
		if test == "n" || test == "N" || test == "no" || test == "No" {
			return false
		}
		return true
	}
	if test == "y" || test == "Y" || test == "yes" || test == "Yes" {
		return true
	}
	return false
}

func simulate(sourceFI osabstraction.FileInfo, destinationFI osabstraction.FileInfo, copyOnly bool, includeSourceFiles bool) (string, error) {
	fs := filesystem.Filesystem{}
	fs.Init()
	err := fs.AddFromRealFilesystem(sourceFI.FullPath())
	if err != nil {
		return "", err
	}
	err = fs.AddFromRealFilesystem(destinationFI.FullPath())
	if err != nil {
		return "", err
	}
	err = flatten.Flatten(sourceFI, destinationFI, fs, copyOnly, includeSourceFiles)
	if err != nil {
		return "", err
	}
	tree := filesystem.Tree{}
	tree.Create(destinationFI, fs)
	return fmt.Sprintf("%v", tree), nil
}

func main() {
	usage := `flatten.

Usage:
  flatten [SOURCE] [DESTINATION] [-c | --copy-only] [-f | --force] [--include-source-files] [-s | --simulate-only] [--verbose]
  flatten -h | --help
  flatten -v

Recursively flatten the directory structure from SOURCE to DESTINATION.

Arguments:
  SOURCE                    Optional source directory (default is current directory).
  DESTINATION               Optional destination directory (default is current directory).

Options:
  -c --copy-only            Do not remove anything from the source directory.
  -f --force                Do not propose a simulation first, immediately execute the command.
  --include-source-files    Include the files which are directly located in the SOURCE directory.
  -s --simulate-only        Do not move or copy any files on the system,
                            just output the expected result.
  -v --version              Show version.
  -h --help                 Show this screen.
  --verbose                 Explain what is being done.`

	arguments, _ := docopt.Parse(usage, nil, true, "flatten "+version, false)

	var source string
	var destination string

	src := arguments["SOURCE"]
	if src == nil {
		p, err := os.Getwd()
		if err != nil {
			fmt.Printf("%v\n", err)
			return
		}
		source = p
	} else {
		source = src.(string)
	}

	dst := arguments["DESTINATION"]
	if dst == nil {
		p, err := os.Getwd()
		if err != nil {
			fmt.Printf("%v\n", err)
			return
		}
		destination = p
	} else {
		destination = dst.(string)
	}

	verbose := arguments["--verbose"].(bool)
	if verbose {
		flatten.SetVerbose()
	}

	includeSourceFiles := arguments["--include-source-files"].(bool)
	copyOnly := arguments["--copy-only"].(bool)
	simulateOnly := arguments["--simulate-only"].(bool)
	force := arguments["--force"].(bool)

	sourceFI := osabstraction.File(path.Clean(source))
	destinationFI := osabstraction.File(path.Clean(destination))

	if !force && !simulateOnly {
		res := ask("flatten performs changes on the file system. Do you want to simulate this process first?", true)
		if !res {
			os.Exit(0)
		}
		force = true
	}

	treeString, err := simulate(sourceFI, destinationFI, copyOnly, includeSourceFiles)
	if err != nil {
		fmt.Println("Could not simulate the process. The following error occured:")
		fmt.Println(err)
		os.Exit(1)
	}

	fmt.Printf(treeString)
	if simulateOnly {
		os.Exit(0)
	}

	if !force {
		res := ask("The above changes will be performed. Do you want to continue?", false)
		if !res {
			os.Exit(0)
		}
	}

	osWrapper := osabstraction.RealOS{}
	err = flatten.Flatten(sourceFI, destinationFI, osWrapper, copyOnly, includeSourceFiles)
	if err != nil {
		fmt.Printf("%v\n", err)
		os.Exit(1)
	}
}
<commit_msg>Correct program logic.<commit_after>package main

import (
	"bufio"
	"fmt"
	"os"
	"path"
	"strings"

	docopt "github.com/docopt/docopt-go"
	"github.com/goggle/flatten/filesystem"
	"github.com/goggle/flatten/flatten"
	"github.com/goggle/flatten/osabstraction"
)

const version = "0.8.0"

func ask(question string, defaultYes bool) bool {
	var defaultString string
	if defaultYes {
		defaultString = "[y]/n:"
	} else {
		defaultString = "y/[n]:"
	}
	reader := bufio.NewReader(os.Stdin)
	fmt.Printf(question + " " + defaultString + " ")
	test, _ := reader.ReadString('\n')
	test = strings.Trim(test, "\n ")
	if defaultYes {
		if test == "n" || test == "N" || test == "no" || test == "No" || test == "NO" {
			return false
		}
		return true
	}
	if test == "y" || test == "Y" || test == "yes" || test == "Yes" || test == "YES" {
		return true
	}
	return false
}

func simulate(sourceFI osabstraction.FileInfo, destinationFI osabstraction.FileInfo, copyOnly bool, includeSourceFiles bool) (string, error) {
	fs := filesystem.Filesystem{}
	fs.Init()
	err := fs.AddFromRealFilesystem(sourceFI.FullPath())
	if err != nil {
		return "", err
	}
	err = fs.AddFromRealFilesystem(destinationFI.FullPath())
	if err != nil {
		return "", err
	}
	err = flatten.Flatten(sourceFI, destinationFI, fs, copyOnly, includeSourceFiles)
	if err != nil {
		return "", err
	}
	tree := filesystem.Tree{}
	tree.Create(destinationFI, fs)
	return fmt.Sprintf("%v", tree), nil
}

func main() {
	usage := `flatten.

Usage:
  flatten [SOURCE] [DESTINATION] [-c | --copy-only] [-f | --force] [--include-source-files] [-s | --simulate-only] [--verbose]
  flatten -h | --help
  flatten -v

Recursively flatten the directory structure from SOURCE to DESTINATION.

Arguments:
  SOURCE                    Optional source directory (default is current directory).
  DESTINATION               Optional destination directory (default is current directory).

Options:
  -c --copy-only            Do not remove anything from the source directory.
  -f --force                Do not propose a simulation first, immediately execute the command.
  --include-source-files    Include the files which are directly located in the SOURCE directory.
  -s --simulate-only        Do not move or copy any files on the system,
                            just output the expected result.
  -v --version              Show version.
  -h --help                 Show this screen.
  --verbose                 Explain what is being done.`

	arguments, _ := docopt.Parse(usage, nil, true, "flatten "+version, false)

	var source string
	var destination string

	src := arguments["SOURCE"]
	if src == nil {
		p, err := os.Getwd()
		if err != nil {
			fmt.Printf("%v\n", err)
			return
		}
		source = p
	} else {
		source = src.(string)
	}

	dst := arguments["DESTINATION"]
	if dst == nil {
		p, err := os.Getwd()
		if err != nil {
			fmt.Printf("%v\n", err)
			return
		}
		destination = p
	} else {
		destination = dst.(string)
	}

	verbose := arguments["--verbose"].(bool)
	if verbose {
		flatten.SetVerbose()
	}

	includeSourceFiles := arguments["--include-source-files"].(bool)
	copyOnly := arguments["--copy-only"].(bool)
	simulateOnly := arguments["--simulate-only"].(bool)
	force := arguments["--force"].(bool)
	performSimulation := false
	askSecondQuestion := true

	sourceFI := osabstraction.File(path.Clean(source))
	destinationFI := osabstraction.File(path.Clean(destination))

	if simulateOnly {
		performSimulation = true
	}

	// Propose to do a simulation first as long we are not in the
	// "force" or "simulation-only" mode:
	if !force && !simulateOnly {
		anw := ask("Flatten performs changes on the file system. Do you want to simulate this process first?", true)
		if anw {
			performSimulation = true
		} else {
			performSimulation = false
			askSecondQuestion = false
		}
	}

	if performSimulation {
		treeString, err := simulate(sourceFI, destinationFI, copyOnly, includeSourceFiles)
		if err != nil {
			fmt.Println("Could not simulate the process. The following error occured:")
			fmt.Println(err)
			os.Exit(1)
		}
		fmt.Printf(treeString)
	}

	// If we are in "simulation-only" mode, we can exit the program
	// at this point.
	if simulateOnly {
		os.Exit(0)
	}

	// Ask the user to continue the process as long as we are not in
	// the "force" mode.
	if !force && askSecondQuestion {
		anw := ask("The above changes will be performed. Do you want to continue?", false)
		if !anw {
			os.Exit(0)
		}
	}

	// Perform the flattening process on the real filesystem:
	osWrapper := osabstraction.RealOS{}
	err := flatten.Flatten(sourceFI, destinationFI, osWrapper, copyOnly, includeSourceFiles)
	if err != nil {
		fmt.Printf("%v\n", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>// Package c2go contains the main function for running the executable.
//
// Installation
//
//     go get -u github.com/elliotchance/c2go
//
// Usage
//
//     c2go myfile.c
//
package main

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"runtime"
	"strings"

	"errors"

	"github.com/elliotchance/c2go/ast"
	"github.com/elliotchance/c2go/preprocessor"
	"github.com/elliotchance/c2go/program"
	"github.com/elliotchance/c2go/transpiler"
)

// Version can be requested through the command line with:
//
//     c2go -v
//
// See https://github.com/elliotchance/c2go/wiki/Release-Process
const Version = "v0.19.4 Uranium 2017-12-27"

var stderr io.Writer = os.Stderr

// ProgramArgs defines the options available when processing the program. There
// is no constructor since the zeroed out values are the appropriate defaults -
// you need only set the options you need.
//
// TODO: Better separation on CLI modes
// https://github.com/elliotchance/c2go/issues/134
//
// Do not instantiate this directly. Instead use DefaultProgramArgs(); then
// modify any specific attributes.
type ProgramArgs struct {
	verbose     bool
	ast         bool
	inputFiles  []string
	clangFlags  []string
	outputFile  string
	packageName string

	// A private option to output the Go as a *_test.go file.
	outputAsTest bool
}

// DefaultProgramArgs default value of ProgramArgs
func DefaultProgramArgs() ProgramArgs {
	return ProgramArgs{
		verbose:      false,
		ast:          false,
		packageName:  "main",
		clangFlags:   []string{},
		outputAsTest: false,
	}
}

func readAST(data []byte) []string {
	return strings.Split(string(data), "\n")
}

type treeNode struct {
	indent int
	node   ast.Node
}

func convertLinesToNodes(lines []string) []treeNode {
	nodes := make([]treeNode, len(lines))
	var counter int
	for _, line := range lines {
		if strings.TrimSpace(line) == "" {
			continue
		}

		// It is tempting to discard null AST nodes, but these may
		// have semantic importance: for example, they represent omitted
		// for-loop conditions, as in for(;;).
		line = strings.Replace(line, "<<<NULL>>>", "NullStmt", 1)
		trimmed := strings.TrimLeft(line, "|\\- `")
		node := ast.Parse(trimmed)
		indentLevel := (len(line) - len(trimmed)) / 2
		nodes[counter] = treeNode{indentLevel, node}
		counter++
	}
	nodes = nodes[0:counter]

	return nodes
}

func convertLinesToNodesParallel(lines []string) []treeNode {
	// function f separate full list on 2 parts and
	// then each part can recursive run function f
	var f func([]string, int) []treeNode

	f = func(lines []string, deep int) []treeNode {
		deep = deep - 2
		part := len(lines) / 2

		var tr1 = make(chan []treeNode)
		var tr2 = make(chan []treeNode)

		go func(lines []string, deep int) {
			if deep <= 0 || len(lines) < deep {
				tr1 <- convertLinesToNodes(lines)
				return
			}
			tr1 <- f(lines, deep)
		}(lines[0:part], deep)

		go func(lines []string, deep int) {
			if deep <= 0 || len(lines) < deep {
				tr2 <- convertLinesToNodes(lines)
				return
			}
			tr2 <- f(lines, deep)
		}(lines[part:], deep)

		defer close(tr1)
		defer close(tr2)

		return append(<-tr1, <-tr2...)
	}

	// Parameter of deep - can be any, but effective to use
	// same amount of CPU
	return f(lines, runtime.NumCPU())
}

// buildTree converts an array of nodes, each prefixed with a depth into a tree.
func buildTree(nodes []treeNode, depth int) []ast.Node {
	if len(nodes) == 0 {
		return []ast.Node{}
	}

	// Split the list into sections, treat each section as a tree with its own
	// root.
	sections := [][]treeNode{}
	for _, node := range nodes {
		if node.indent == depth {
			sections = append(sections, []treeNode{node})
		} else {
			sections[len(sections)-1] = append(sections[len(sections)-1], node)
		}
	}

	results := []ast.Node{}
	for _, section := range sections {
		slice := []treeNode{}
		for _, n := range section {
			if n.indent > depth {
				slice = append(slice, n)
			}
		}

		children := buildTree(slice, depth+1)
		for _, child := range children {
			section[0].node.AddChild(child)
		}
		results = append(results, section[0].node)
	}

	return results
}

// Start begins transpiling an input file.
func Start(args ProgramArgs) (err error) {
	if args.verbose {
		fmt.Println("Start tanspiling ...")
	}

	if os.Getenv("GOPATH") == "" {
		return fmt.Errorf("The $GOPATH must be set")
	}

	// 1. Compile it first (checking for errors)
	for _, in := range args.inputFiles {
		_, err := os.Stat(in)
		if err != nil {
			return fmt.Errorf("Input file %s is not found", in)
		}
	}

	// 2. Preprocess
	if args.verbose {
		fmt.Println("Running clang preprocessor...")
	}

	pp, err := preprocessor.Analyze(args.inputFiles, args.clangFlags)
	if err != nil {
		return err
	}

	if args.verbose {
		fmt.Println("Writing preprocessor ...")
	}
	dir, err := ioutil.TempDir("", "c2go")
	if err != nil {
		return fmt.Errorf("Cannot create temp folder: %v", err)
	}
	defer os.RemoveAll(dir) // clean up

	ppFilePath := path.Join(dir, "pp.c")
	err = ioutil.WriteFile(ppFilePath, pp, 0644)
	if err != nil {
		return fmt.Errorf("writing to %s failed: %v", ppFilePath, err)
	}

	// 3. Generate JSON from AST
	if args.verbose {
		fmt.Println("Running clang for AST tree...")
	}
	astPP, err := exec.Command("clang", "-Xclang", "-ast-dump", "-fsyntax-only", "-fno-color-diagnostics", ppFilePath).Output()
	if err != nil {
		// If clang fails it still prints out the AST, so we have to run it
		// again to get the real error.
		errBody, _ := exec.Command("clang", ppFilePath).CombinedOutput()

		panic("clang failed: " + err.Error() + ":\n\n" + string(errBody))
	}

	if args.verbose {
		fmt.Println("Reading clang AST tree...")
	}
	lines := readAST(astPP)
	if args.ast {
		for _, l := range lines {
			fmt.Println(l)
		}
		fmt.Println()

		return nil
	}

	p := program.NewProgram()
	p.Verbose = args.verbose
	p.OutputAsTest = args.outputAsTest

	// Converting to nodes
	if args.verbose {
		fmt.Println("Converting to nodes...")
	}
	nodes := convertLinesToNodesParallel(lines)

	// build tree
	if args.verbose {
		fmt.Println("Building tree...")
	}
	tree := buildTree(nodes, 0)
	ast.FixPositions(tree)

	// Repair the floating literals. See RepairFloatingLiteralsFromSource for
	// more information.
	floatingErrors := ast.RepairFloatingLiteralsFromSource(tree[0], ppFilePath)

	for _, fErr := range floatingErrors {
		message := fmt.Sprintf("could not read exact floating literal: %s",
			fErr.Err.Error())
		p.AddMessage(p.GenerateWarningMessage(errors.New(message), fErr.Node))
	}

	outputFilePath := args.outputFile

	if outputFilePath == "" {
		// Choose inputFile for creating name of output file
		input := args.inputFiles[0]
		// We choose name for output Go code at the base
		// on filename for choosed input file
		cleanFileName := filepath.Clean(filepath.Base(input))
		extension := filepath.Ext(input)
		outputFilePath = cleanFileName[0:len(cleanFileName)-len(extension)] + ".go"
	}

	// transpile ast tree
	if args.verbose {
		fmt.Println("Transpiling tree...")
	}

	err = transpiler.TranspileAST(args.outputFile, args.packageName, p, tree[0].(ast.Node))
	if err != nil {
		return fmt.Errorf("cannot transpile AST : %v", err)
	}

	// write the output Go code
	if args.verbose {
		fmt.Println("Writing the output Go code...")
	}
	err = ioutil.WriteFile(outputFilePath, []byte(p.String()), 0644)
	if err != nil {
		return fmt.Errorf("writing Go output file failed: %v", err)
	}

	return nil
}

type inputDataFlags []string

func (i *inputDataFlags) String() (s string) {
	for pos, item := range *i {
		s += fmt.Sprintf("Flag %d. %s\n", pos, item)
	}
	return
}

func (i *inputDataFlags) Set(value string) error {
	*i = append(*i, value)
	return nil
}

var clangFlags inputDataFlags

func init() {
	transpileCommand.Var(&clangFlags, "clang-flag", "Pass arguments to clang. You may provide multiple -clang-flag items.")
}

var (
	versionFlag       = flag.Bool("v", false, "print the version and exit")
	transpileCommand  = flag.NewFlagSet("transpile", flag.ContinueOnError)
	verboseFlag       = transpileCommand.Bool("V", false, "print progress as comments")
	outputFlag        = transpileCommand.String("o", "", "output Go generated code to the specified file")
	packageFlag       = transpileCommand.String("p", "main", "set the name of the generated package")
	transpileHelpFlag = transpileCommand.Bool("h", false, "print help information")
	astCommand        = flag.NewFlagSet("ast", flag.ContinueOnError)
	astHelpFlag       = astCommand.Bool("h", false, "print help information")
)

func main() {
	code := runCommand()
	if code != 0 {
		os.Exit(code)
	}
}

func runCommand() int {

	flag.Usage = func() {
		usage := "Usage: %s [-v] [<command>] [<flags>] file1.c ...\n\n"
		usage += "Commands:\n"
		usage += "  transpile\ttranspile an input C source file or files to Go\n"
		usage += "  ast\t\tprint AST before translated Go code\n\n"

		usage += "Flags:\n"
		fmt.Fprintf(stderr, usage, os.Args[0])
		flag.PrintDefaults()
	}

	transpileCommand.SetOutput(stderr)
	astCommand.SetOutput(stderr)

	flag.Parse()

	if *versionFlag {
		// Simply print out the version and exit.
		fmt.Println(Version)
		return 0
	}

	if flag.NArg() < 1 {
		flag.Usage()
		return 1
	}

	args := DefaultProgramArgs()

	switch os.Args[1] {
	case "ast":
		err := astCommand.Parse(os.Args[2:])
		if err != nil {
			fmt.Printf("ast command cannot parse: %v", err)
			return 1
		}

		if *astHelpFlag || astCommand.NArg() == 0 {
			fmt.Fprintf(stderr, "Usage: %s ast file.c\n", os.Args[0])
			astCommand.PrintDefaults()
			return 1
		}

		args.ast = true
		args.inputFiles = astCommand.Args()
	case "transpile":
		err := transpileCommand.Parse(os.Args[2:])
		if err != nil {
			fmt.Printf("transpile command cannot parse: %v", err)
			return 1
		}

		if *transpileHelpFlag || transpileCommand.NArg() == 0 {
			fmt.Fprintf(stderr, "Usage: %s transpile [-V] [-o file.go] [-p package] file1.c ...\n", os.Args[0])
			transpileCommand.PrintDefaults()
			return 1
		}

		args.inputFiles = transpileCommand.Args()
		args.outputFile = *outputFlag
		args.packageName = *packageFlag
		args.verbose = *verboseFlag
		args.clangFlags = clangFlags
	default:
		flag.Usage()
		return 1
	}

	if err := Start(args); err != nil {
		fmt.Printf("Error: %v\n", err)
		return 1
	}

	return 0
}
<commit_msg>Bump version: v0.19.5 Uranium 2018-01-01<commit_after>// Package c2go contains the main function for running the executable.
//
// Installation
//
//     go get -u github.com/elliotchance/c2go
//
// Usage
//
//     c2go myfile.c
//
package main

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"runtime"
	"strings"

	"errors"

	"github.com/elliotchance/c2go/ast"
	"github.com/elliotchance/c2go/preprocessor"
	"github.com/elliotchance/c2go/program"
	"github.com/elliotchance/c2go/transpiler"
)

// Version can be requested through the command line with:
//
//     c2go -v
//
// See https://github.com/elliotchance/c2go/wiki/Release-Process
const Version = "v0.19.5 Uranium 2018-01-01"

var stderr io.Writer = os.Stderr

// ProgramArgs defines the options available when processing the program. There
// is no constructor since the zeroed out values are the appropriate defaults -
// you need only set the options you need.
//
// TODO: Better separation on CLI modes
// https://github.com/elliotchance/c2go/issues/134
//
// Do not instantiate this directly. Instead use DefaultProgramArgs(); then
// modify any specific attributes.
type ProgramArgs struct {
	verbose     bool
	ast         bool
	inputFiles  []string
	clangFlags  []string
	outputFile  string
	packageName string

	// A private option to output the Go as a *_test.go file.
	outputAsTest bool
}

// DefaultProgramArgs default value of ProgramArgs
func DefaultProgramArgs() ProgramArgs {
	return ProgramArgs{
		verbose:      false,
		ast:          false,
		packageName:  "main",
		clangFlags:   []string{},
		outputAsTest: false,
	}
}

func readAST(data []byte) []string {
	return strings.Split(string(data), "\n")
}

type treeNode struct {
	indent int
	node   ast.Node
}

func convertLinesToNodes(lines []string) []treeNode {
	nodes := make([]treeNode, len(lines))
	var counter int
	for _, line := range lines {
		if strings.TrimSpace(line) == "" {
			continue
		}

		// It is tempting to discard null AST nodes, but these may
		// have semantic importance: for example, they represent omitted
		// for-loop conditions, as in for(;;).
		line = strings.Replace(line, "<<<NULL>>>", "NullStmt", 1)
		trimmed := strings.TrimLeft(line, "|\\- `")
		node := ast.Parse(trimmed)
		indentLevel := (len(line) - len(trimmed)) / 2
		nodes[counter] = treeNode{indentLevel, node}
		counter++
	}
	nodes = nodes[0:counter]

	return nodes
}

func convertLinesToNodesParallel(lines []string) []treeNode {
	// function f separate full list on 2 parts and
	// then each part can recursive run function f
	var f func([]string, int) []treeNode

	f = func(lines []string, deep int) []treeNode {
		deep = deep - 2
		part := len(lines) / 2

		var tr1 = make(chan []treeNode)
		var tr2 = make(chan []treeNode)

		go func(lines []string, deep int) {
			if deep <= 0 || len(lines) < deep {
				tr1 <- convertLinesToNodes(lines)
				return
			}
			tr1 <- f(lines, deep)
		}(lines[0:part], deep)

		go func(lines []string, deep int) {
			if deep <= 0 || len(lines) < deep {
				tr2 <- convertLinesToNodes(lines)
				return
			}
			tr2 <- f(lines, deep)
		}(lines[part:], deep)

		defer close(tr1)
		defer close(tr2)

		return append(<-tr1, <-tr2...)
	}

	// Parameter of deep - can be any, but effective to use
	// same amount of CPU
	return f(lines, runtime.NumCPU())
}

// buildTree converts an array of nodes, each prefixed with a depth into a tree.
func buildTree(nodes []treeNode, depth int) []ast.Node {
	if len(nodes) == 0 {
		return []ast.Node{}
	}

	// Split the list into sections, treat each section as a tree with its own
	// root.
	sections := [][]treeNode{}
	for _, node := range nodes {
		if node.indent == depth {
			sections = append(sections, []treeNode{node})
		} else {
			sections[len(sections)-1] = append(sections[len(sections)-1], node)
		}
	}

	results := []ast.Node{}
	for _, section := range sections {
		slice := []treeNode{}
		for _, n := range section {
			if n.indent > depth {
				slice = append(slice, n)
			}
		}

		children := buildTree(slice, depth+1)
		for _, child := range children {
			section[0].node.AddChild(child)
		}
		results = append(results, section[0].node)
	}

	return results
}

// Start begins transpiling an input file.
func Start(args ProgramArgs) (err error) {
	if args.verbose {
		fmt.Println("Start tanspiling ...")
	}

	if os.Getenv("GOPATH") == "" {
		return fmt.Errorf("The $GOPATH must be set")
	}

	// 1. Compile it first (checking for errors)
	for _, in := range args.inputFiles {
		_, err := os.Stat(in)
		if err != nil {
			return fmt.Errorf("Input file %s is not found", in)
		}
	}

	// 2. Preprocess
	if args.verbose {
		fmt.Println("Running clang preprocessor...")
	}

	pp, err := preprocessor.Analyze(args.inputFiles, args.clangFlags)
	if err != nil {
		return err
	}

	if args.verbose {
		fmt.Println("Writing preprocessor ...")
	}
	dir, err := ioutil.TempDir("", "c2go")
	if err != nil {
		return fmt.Errorf("Cannot create temp folder: %v", err)
	}
	defer os.RemoveAll(dir) // clean up

	ppFilePath := path.Join(dir, "pp.c")
	err = ioutil.WriteFile(ppFilePath, pp, 0644)
	if err != nil {
		return fmt.Errorf("writing to %s failed: %v", ppFilePath, err)
	}

	// 3. Generate JSON from AST
	if args.verbose {
		fmt.Println("Running clang for AST tree...")
	}
	astPP, err := exec.Command("clang", "-Xclang", "-ast-dump", "-fsyntax-only", "-fno-color-diagnostics", ppFilePath).Output()
	if err != nil {
		// If clang fails it still prints out the AST, so we have to run it
		// again to get the real error.
		errBody, _ := exec.Command("clang", ppFilePath).CombinedOutput()

		panic("clang failed: " + err.Error() + ":\n\n" + string(errBody))
	}

	if args.verbose {
		fmt.Println("Reading clang AST tree...")
	}
	lines := readAST(astPP)
	if args.ast {
		for _, l := range lines {
			fmt.Println(l)
		}
		fmt.Println()

		return nil
	}

	p := program.NewProgram()
	p.Verbose = args.verbose
	p.OutputAsTest = args.outputAsTest

	// Converting to nodes
	if args.verbose {
		fmt.Println("Converting to nodes...")
	}
	nodes := convertLinesToNodesParallel(lines)

	// build tree
	if args.verbose {
		fmt.Println("Building tree...")
	}
	tree := buildTree(nodes, 0)
	ast.FixPositions(tree)

	// Repair the floating literals. See RepairFloatingLiteralsFromSource for
	// more information.
	floatingErrors := ast.RepairFloatingLiteralsFromSource(tree[0], ppFilePath)

	for _, fErr := range floatingErrors {
		message := fmt.Sprintf("could not read exact floating literal: %s",
			fErr.Err.Error())
		p.AddMessage(p.GenerateWarningMessage(errors.New(message), fErr.Node))
	}

	outputFilePath := args.outputFile

	if outputFilePath == "" {
		// Choose inputFile for creating name of output file
		input := args.inputFiles[0]
		// We choose name for output Go code at the base
		// on filename for choosed input file
		cleanFileName := filepath.Clean(filepath.Base(input))
		extension := filepath.Ext(input)
		outputFilePath = cleanFileName[0:len(cleanFileName)-len(extension)] + ".go"
	}

	// transpile ast tree
	if args.verbose {
		fmt.Println("Transpiling tree...")
	}

	err = transpiler.TranspileAST(args.outputFile, args.packageName, p, tree[0].(ast.Node))
	if err != nil {
		return fmt.Errorf("cannot transpile AST : %v", err)
	}

	// write the output Go code
	if args.verbose {
		fmt.Println("Writing the output Go code...")
	}
	err = ioutil.WriteFile(outputFilePath, []byte(p.String()), 0644)
	if err != nil {
		return fmt.Errorf("writing Go output file failed: %v", err)
	}

	return nil
}

type inputDataFlags []string

func (i *inputDataFlags) String() (s string) {
	for pos, item := range *i {
		s += fmt.Sprintf("Flag %d. %s\n", pos, item)
	}
	return
}

func (i *inputDataFlags) Set(value string) error {
	*i = append(*i, value)
	return nil
}

var clangFlags inputDataFlags

func init() {
	transpileCommand.Var(&clangFlags, "clang-flag", "Pass arguments to clang. You may provide multiple -clang-flag items.")
}

var (
	versionFlag       = flag.Bool("v", false, "print the version and exit")
	transpileCommand  = flag.NewFlagSet("transpile", flag.ContinueOnError)
	verboseFlag       = transpileCommand.Bool("V", false, "print progress as comments")
	outputFlag        = transpileCommand.String("o", "", "output Go generated code to the specified file")
	packageFlag       = transpileCommand.String("p", "main", "set the name of the generated package")
	transpileHelpFlag = transpileCommand.Bool("h", false, "print help information")
	astCommand        = flag.NewFlagSet("ast", flag.ContinueOnError)
	astHelpFlag       = astCommand.Bool("h", false, "print help information")
)

func main() {
	code := runCommand()
	if code != 0 {
		os.Exit(code)
	}
}

func runCommand() int {

	flag.Usage = func() {
		usage := "Usage: %s [-v] [<command>] [<flags>] file1.c ...\n\n"
		usage += "Commands:\n"
		usage += "  transpile\ttranspile an input C source file or files to Go\n"
		usage += "  ast\t\tprint AST before translated Go code\n\n"

		usage += "Flags:\n"
		fmt.Fprintf(stderr, usage, os.Args[0])
		flag.PrintDefaults()
	}

	transpileCommand.SetOutput(stderr)
	astCommand.SetOutput(stderr)

	flag.Parse()

	if *versionFlag {
		// Simply print out the version and exit.
		fmt.Println(Version)
		return 0
	}

	if flag.NArg() < 1 {
		flag.Usage()
		return 1
	}

	args := DefaultProgramArgs()

	switch os.Args[1] {
	case "ast":
		err := astCommand.Parse(os.Args[2:])
		if err != nil {
			fmt.Printf("ast command cannot parse: %v", err)
			return 1
		}

		if *astHelpFlag || astCommand.NArg() == 0 {
			fmt.Fprintf(stderr, "Usage: %s ast file.c\n", os.Args[0])
			astCommand.PrintDefaults()
			return 1
		}

		args.ast = true
		args.inputFiles = astCommand.Args()
	case "transpile":
		err := transpileCommand.Parse(os.Args[2:])
		if err != nil {
			fmt.Printf("transpile command cannot parse: %v", err)
			return 1
		}

		if *transpileHelpFlag || transpileCommand.NArg() == 0 {
			fmt.Fprintf(stderr, "Usage: %s transpile [-V] [-o file.go] [-p package] file1.c ...\n", os.Args[0])
			transpileCommand.PrintDefaults()
			return 1
		}

		args.inputFiles = transpileCommand.Args()
		args.outputFile = *outputFlag
		args.packageName = *packageFlag
		args.verbose = *verboseFlag
		args.clangFlags = clangFlags
	default:
		flag.Usage()
		return 1
	}

	if err := Start(args); err != nil {
		fmt.Printf("Error: %v\n", err)
		return 1
	}

	return 0
}
<|endoftext|>


<commit_before>package main

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

	"gopkg.in/fsnotify.v1"
)

func main() {
	path, err := filepath.Abs(".")
	if err != nil {
		panic(err)
	}

	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		panic(err)
	}

	err = watcher.Add(path)
	if err != nil {
		panic(err)
	}
	defer watcher.Close()

	fmt.Println("Watching:", path)

	for event := range watcher.Events {
		fmt.Println(event)
		if event.Op == fsnotify.Create || event.Op == fsnotify.Write {
			if filepath.Ext(event.Name) == ".go" {
				fmt.Println("Formatting")
				command := exec.Command("gofmt", "-w", event.Name)
				command.Start()
				command.Wait()
			}
		}
	}
}
<commit_msg>Watch main package source files and run when they're created/updated<commit_after>package main

import (
	"fmt"
	"go/parser"
	"go/token"
	"os"
	"os/exec"
	"path/filepath"

	"gopkg.in/fsnotify.v1"
)

func getPackageNameAndImport(sourceName string) (packageName string, imports []string) {
	fset := token.NewFileSet() // positions are relative to fset

	// Parse the file containing this very example
	// but stop after processing the imports.
	f, err := parser.ParseFile(fset, sourceName, nil, parser.ImportsOnly)
	if err != nil {
		fmt.Println(err)
		return
	}

	// Print the imports from the file's AST.
	packageName = f.Name.Name

	for _, s := range f.Imports {
		importedPackageName := s.Path.Value[1 : len(s.Path.Value)-1]
		imports = append(imports, importedPackageName)
	}

	return
}

func main() {
	path, err := filepath.Abs(".")
	if err != nil {
		panic(err)
	}

	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		panic(err)
	}

	err = watcher.Add(path)
	if err != nil {
		panic(err)
	}
	defer watcher.Close()

	fmt.Println("Watching:", path)

	command := exec.Command("gofmt", "-w", ".")
	command.Run()

	for event := range watcher.Events {
		if event.Op == fsnotify.Create || event.Op == fsnotify.Write {
			if filepath.Ext(event.Name) == ".go" {
				command := exec.Command("gofmt", "-w", event.Name)
				command.Run()

				packageName, _ := getPackageNameAndImport(event.Name)
				if packageName == "main" {
					fmt.Println("Run file:", event.Name)
					command = exec.Command("go", "run", event.Name)
					command.Stdout = os.Stdout
					command.Run()
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
    "os"
    "os/exec"

    "io/ioutil"

    "log"

//    "fmt"
    "strings"
    "runtime"
    "strconv" // For Itoa
//    "encoding/csv"
    "encoding/json"

    "github.com/go-martini/martini"
)

func main() {
    m := martini.Classic()

    // CPU count
    m.Get("/sh/numberofcores.php", func () ([]byte, error) {
        return json.Marshal(runtime.NumCPU())
    })

    // Server's hostname
    m.Get("/sh/hostname.php", func () ([]byte, error) {
        host, err := os.Hostname()

        if err != nil {
            return nil, err
        }

        return json.Marshal(host)
    })

    // PS
    m.Get("/sh/ps.php", func () ([]byte, error) {
        // Run uptime command
        rawOutput, err := exec.Command("ps", "aux").Output()

        if err != nil {
            return nil, err
        }

        return json.Marshal(parseCommandTable(rawOutput, 1, 1))
    })

    m.Get("/sh/df.php", func () ([]byte, error) {
        // Run uptime command
        rawOutput, err := exec.Command("df", "-Ph").Output()

        if err != nil {
            return nil, err
        }

        return json.Marshal(parseCommandTable(rawOutput, 1, 1))
    })

    m.Get("/sh/time.php", func () ([]byte, error) {
        raw, err := exec.Command("date").Output()

        if err != nil {
            return nil, err
        }

        return json.Marshal(string(raw[:]))
    })

    m.Get("/sh/issue.php", func () ([]byte, error) {
        raw, err := exec.Command("uname", "-rsm").Output()

        if err != nil {
            return nil, err
        }

        return json.Marshal(string(raw[:]))
    })

    m.Get("/sh/users.php", func () ([]byte, error) {
        data, err := ioutil.ReadFile("/etc/passwd")

        if err != nil {
            return nil, err
        }

        lines := strings.Split(string(data), "\n")

        // Output records
        var records [][]string

        for _, line := range lines {
            parts := strings.Split(line, ":")

            // Skip bad or empty lines
            if len(parts) != 7 {
                log.Println(len(parts))
                continue
            }

            // Parse base 10, 16 bit UID integer
            uid, err := strconv.ParseInt(parts[2], 10, 16)

            // Error parsing UID
            if err != nil {
                continue
            }

            userType := "user"

            // Check if system user
            if uid <= 499 {
                userType = "system"
            }

            user := []string{
                // User type
                userType,
                // Username
                parts[0],
                // Home directory
                parts[6],
            }

            records = append(records, user)
        }

        return json.Marshal(records)
    })

    m.Get("/sh/online.php", func () ([]byte, error) {
        raw, err := exec.Command("w").Output()

        if err != nil {
            return nil, err
        }

        // We'll add all the parsed lines here
        var entries [][]string

        // Skip first and last line of output
        for _, entry := range parseCommandTable(raw, 2, 1) {
            entries = append(entries, []string{
                // User
                entry[0],
                // From
                entry[2],
                // Login at
                entry[3],
                // Idle
                entry[4],
            })
        }

        return json.Marshal(entries)
    })

    // Serve static files
    m.Get("/.*", martini.Static(""))

    m.Run()
}

func parseCommandTable(rawOutput []byte, headerCount int, footerCount int) [][]string {
    // Convert output to a string (it's not binary data, so this is ok)
    output := string(rawOutput[:])

    // We'll add all the parsed lines here
    var entries [][]string

    // Lines of output
    lines := strings.Split(output, "\n")

    // Skip first and last line of output
    for _, str := range lines[headerCount:len(lines)-footerCount] {
        entries = append(entries, strings.Fields(str))
    }

    return entries
}
<commit_msg>Add loadavg command<commit_after>package main

import (
    "os"
    "os/exec"

    "io/ioutil"

    "log"

//    "fmt"
    "strings"
    "runtime"
    "strconv" // For Itoa
//    "encoding/csv"
    "encoding/json"

    "github.com/go-martini/martini"
)

func main() {
    m := martini.Classic()

    // CPU count
    m.Get("/sh/numberofcores.php", func () ([]byte, error) {
        return json.Marshal(runtime.NumCPU())
    })

    // Server's hostname
    m.Get("/sh/hostname.php", func () ([]byte, error) {
        host, err := os.Hostname()

        if err != nil {
            return nil, err
        }

        return json.Marshal(host)
    })

    // PS
    m.Get("/sh/ps.php", func () ([]byte, error) {
        // Run uptime command
        rawOutput, err := exec.Command("ps", "aux").Output()

        if err != nil {
            return nil, err
        }

        return json.Marshal(parseCommandTable(rawOutput, 1, 1))
    })

    m.Get("/sh/df.php", func () ([]byte, error) {
        // Run uptime command
        rawOutput, err := exec.Command("df", "-Ph").Output()

        if err != nil {
            return nil, err
        }

        return json.Marshal(parseCommandTable(rawOutput, 1, 1))
    })

    m.Get("/sh/time.php", func () ([]byte, error) {
        raw, err := exec.Command("date").Output()

        if err != nil {
            return nil, err
        }

        return json.Marshal(string(raw[:]))
    })

    m.Get("/sh/issue.php", func () ([]byte, error) {
        raw, err := exec.Command("uname", "-rsm").Output()

        if err != nil {
            return nil, err
        }

        return json.Marshal(string(raw[:]))
    })

    m.Get("/sh/users.php", func () ([]byte, error) {
        data, err := ioutil.ReadFile("/etc/passwd")

        if err != nil {
            return nil, err
        }

        lines := strings.Split(string(data), "\n")

        // Output records
        var records [][]string

        for _, line := range lines {
            parts := strings.Split(line, ":")

            // Skip bad or empty lines
            if len(parts) != 7 {
                log.Println(len(parts))
                continue
            }

            // Parse base 10, 16 bit UID integer
            uid, err := strconv.ParseInt(parts[2], 10, 16)

            // Error parsing UID
            if err != nil {
                continue
            }

            userType := "user"

            // Check if system user
            if uid <= 499 {
                userType = "system"
            }

            user := []string{
                // User type
                userType,
                // Username
                parts[0],
                // Home directory
                parts[6],
            }

            records = append(records, user)
        }

        return json.Marshal(records)
    })

    m.Get("/sh/online.php", func () ([]byte, error) {
        raw, err := exec.Command("w").Output()

        if err != nil {
            return nil, err
        }

        // We'll add all the parsed lines here
        var entries [][]string

        // Skip first and last line of output
        for _, entry := range parseCommandTable(raw, 2, 1) {
            entries = append(entries, []string{
                // User
                entry[0],
                // From
                entry[2],
                // Login at
                entry[3],
                // Idle
                entry[4],
            })
        }

        return json.Marshal(entries)
    })

    m.Get("/sh/loadavg.php", func () ([]byte, error) {
        raw, err := exec.Command("w").Output()

        if err != nil {
            return nil, err
        }

        lines := strings.Split(string(raw[:]), "\n")
        headers := strings.Fields(lines[0])

        var cpuLoads [][2]string

        // Last 3 headers are CPU loads, clean them up
        for _, load := range headers[len(headers)-3:] {
            // Remove trailing coma if there
            cleanLoad := strings.Split(string(load), ",")[0]

            loadFloat, err := strconv.ParseFloat(cleanLoad, 32)

            if err != nil {
                continue
            }

            loadPercentage := int(loadFloat * 100) / runtime.NumCPU()

            cpuLoads = append(cpuLoads, [2]string{
                cleanLoad,
                strconv.Itoa(loadPercentage),
            })
        }

        return json.Marshal(cpuLoads)
    })

    // Serve static files
    m.Get("/.*", martini.Static(""))

    m.Run()
}

func parseCommandTable(rawOutput []byte, headerCount int, footerCount int) [][]string {
    // Convert output to a string (it's not binary data, so this is ok)
    output := string(rawOutput[:])

    // We'll add all the parsed lines here
    var entries [][]string

    // Lines of output
    lines := strings.Split(output, "\n")

    // Skip first and last line of output
    for _, str := range lines[headerCount:len(lines)-footerCount] {
        entries = append(entries, strings.Fields(str))
    }

    return entries
}
<|endoftext|>


<commit_before><commit_msg>Dotting i's.<commit_after><|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/service/ssm"
	"github.com/jamietsao/aws-ssm-env/fetch"
)

var (
	paths []string
	tags  []string
	debug bool
)

func main() {

	// initialize command line flags
	initFlags()

	// fetch parameters
	start := time.Now()
	fetcher := fetch.NewFetcher(paths, tags, os.Getenv("SSM_REGION"), debug)
	params, err := fetcher.FetchParams(paths, tags)
	if err != nil {
		panic(err)
	}
	elapsed := time.Since(start)

	debugf("Params retrieved in %s\n", elapsed)

	// print as env variables
	printParams(params)
}

func initFlags() {
	pathsFlag := flag.String("paths", "", "comma delimited string of parameter path hierarchies (optional)")
	tagsFlag := flag.String("tags", "", "comma delimited string of tags to filter by (optional)")
	flag.BoolVar(&debug, "debug", false, "Enables debug logging when set to true")
	flag.Parse()

	if *pathsFlag == "" && *tagsFlag == "" {
		fmt.Print("Flag required: Either --paths or --tags is required\n\n")
		flag.Usage()
		os.Exit(1)
	}

	initPaths(pathsFlag)
	initTags(tagsFlag)
}

func initPaths(pathsFlag *string) {
	if *pathsFlag != "" {
		paths = strings.Split(*pathsFlag, ",")
	}

	// ensure only path hierarchies were given
	for _, path := range paths {
		if !strings.Contains(path, "/") {
			fmt.Printf("Invalid path: '%s' - only path hierarchies are supported (e.g. '/production/webapp/')\n", path)
			os.Exit(1)
		}
	}
}

func initTags(tagsFlag *string) {
	if *tagsFlag != "" {
		tags = strings.Split(*tagsFlag, ",")
	}
}

func printParams(params []*ssm.Parameter) {
	for _, param := range params {
		split := strings.Split(*param.Name, "/")
		name := split[len(split)-1]
		fmt.Printf("%s=%s\n", strings.ToUpper(name), *param.Value)
	}
}

func getParamNameValues(params []*ssm.Parameter) map[string]string {
	paramVals := make(map[string]string, len(params))
	for _, param := range params {
		split := strings.Split(*param.Name, "/")
		name := split[len(split)-1]
		paramVals[strings.ToUpper(name)] = *param.Value
	}
	return paramVals
}

func debugf(format string, a ...interface{}) {
	if debug {
		fmt.Printf("DEBUG -- %s", fmt.Sprintf(format, a...))
	}
}
<commit_msg>Remove unused duplicate func<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/service/ssm"
	"github.com/jamietsao/aws-ssm-env/fetch"
)

var (
	paths []string
	tags  []string
	debug bool
)

func main() {

	// initialize command line flags
	initFlags()

	// fetch parameters
	start := time.Now()
	fetcher := fetch.NewFetcher(paths, tags, os.Getenv("SSM_REGION"), debug)
	params, err := fetcher.FetchParams(paths, tags)
	if err != nil {
		panic(err)
	}
	elapsed := time.Since(start)

	debugf("Params retrieved in %s\n", elapsed)

	// print as env variables
	printParams(params)
}

func initFlags() {
	pathsFlag := flag.String("paths", "", "comma delimited string of parameter path hierarchies (optional)")
	tagsFlag := flag.String("tags", "", "comma delimited string of tags to filter by (optional)")
	flag.BoolVar(&debug, "debug", false, "Enables debug logging when set to true")
	flag.Parse()

	if *pathsFlag == "" && *tagsFlag == "" {
		fmt.Print("Flag required: Either --paths or --tags is required\n\n")
		flag.Usage()
		os.Exit(1)
	}

	initPaths(pathsFlag)
	initTags(tagsFlag)
}

func initPaths(pathsFlag *string) {
	if *pathsFlag != "" {
		paths = strings.Split(*pathsFlag, ",")
	}

	// ensure only path hierarchies were given
	for _, path := range paths {
		if !strings.Contains(path, "/") {
			fmt.Printf("Invalid path: '%s' - only path hierarchies are supported (e.g. '/production/webapp/')\n", path)
			os.Exit(1)
		}
	}
}

func initTags(tagsFlag *string) {
	if *tagsFlag != "" {
		tags = strings.Split(*tagsFlag, ",")
	}
}

func printParams(params []*ssm.Parameter) {
	for _, param := range params {
		split := strings.Split(*param.Name, "/")
		name := split[len(split)-1]
		fmt.Printf("%s=%s\n", strings.ToUpper(name), *param.Value)
	}
}

func debugf(format string, a ...interface{}) {
	if debug {
		fmt.Printf("DEBUG -- %s", fmt.Sprintf(format, a...))
	}
}
<|endoftext|>


<commit_before>package main

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

func cat(c chan string, e chan error, quit chan struct{}) {
	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		c <- scanner.Text()
	}
	if err := scanner.Err(); err != nil {
		e <- err
	}
	quit <- struct{}{}
}

func main() {
	var timeoutSeconds float64
	var begin, end, h, help bool

	flag.Float64Var(&timeoutSeconds, "timeout", 1, "amount of time between output")
	flag.BoolVar(&begin, "beginEdge", false, "trigger at start")
	flag.BoolVar(&end, "endEdge", true, "trigger at end")
	flag.BoolVar(&h, "h", false, "help for debounce")
	flag.BoolVar(&help, "help", false, "help for debounce")

	flag.Parse()

	if h || help {
		fmt.Println("\n" +
			" debounce          [--beginEdge] [--endEdge] [--timeout 2] [-h|--help]\n" +
			"    --beginEdge     pass this flag to output at the start of a cycle\n" +
			"    --endEdge       pass this flag to output after the end of a cycle\n" +
			"    --timeout       set the timeout in seconds, default is 1 second\n" +
			"\n" +
			"    -h --help       print usage message and exit\n",
		)
		return
	}

	c := make(chan string)
	quit := make(chan struct{})
	err := make(chan error)

	go cat(c, err, quit)

	for {
		var x string
		shouldPrint := false
		select {
		case x = <-c:
			shouldPrint = true
			if begin {
				shouldPrint = false
				fmt.Println(x)
			}
		case x := <-err:
			fmt.Fprintln(os.Stderr, "reading standard input:", x)
		case <-quit:
			return
		}
		timeout := time.After(time.Duration(timeoutSeconds) * time.Second)
	InnerLoop:
		for {
			select {
			case x = <-c:
				shouldPrint = true
				timeout = time.After(time.Duration(timeoutSeconds) * time.Second)
			case x := <-err:
				fmt.Fprintln(os.Stderr, "reading standard input:", x)
			case <-quit:
				return
			case <-timeout:
				if end && shouldPrint {
					fmt.Println(x)
				}
				break InnerLoop
			}
		}
	}
}
<commit_msg>change interface and add docs<commit_after>package main

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

func cat(c chan string, e chan error, quit chan struct{}) {
	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		c <- scanner.Text()
	}
	if err := scanner.Err(); err != nil {
		e <- err
	}
	quit <- struct{}{}
}

func main() {
	var timeoutSeconds float64
	var begin, end, h, help bool

	flag.Float64Var(&timeoutSeconds, "lockoutTime", 1, "amount of time between output")
	flag.BoolVar(&begin, "leadingEdge", false, "trigger at leading edge of cycle")
	flag.BoolVar(&end, "trailingEdge", true, "trigger at trailing edge of cycle")
	flag.BoolVar(&h, "h", false, "help for debounce")
	flag.BoolVar(&help, "help", false, "help for debounce")

	flag.Parse()

	if h || help {
		fmt.Println("\n" +
			" debounce          [--leadingEdge] [--trailingEdge] [--timeout 2]\n" +
			"                   [-h|--help]\n" +
			"\n" +
			"    --leadingEdge   pass this flag to output at the leading edge of a cycle\n" +
			"                    (off by default)\n" +
			"    --trailingEdge  pass this flag to output at the trailing edge of a cycle\n" +
			"                    (on by default, pass false to disable)\n" +
			"    --lockoutTime   set the lockout time in seconds, default is 1 second\n" +
			"\n" +
			"    -h --help       print usage message and exit\n" +
			"\n" +
			"\n" +
			"debounce creates cycles based on the lockout time.  The cycle\n" +
			"starts on the first line sent and stops after no lines are sent\n" +
			"within a period of the lockout time\n" +
			"\n" +
			"\n" +
			"The following would run tests after a second of 'silence' after a\n" +
			"save\n" +
			"\n" +
			" inotifywait -mr -e modify,move . | debounce | xargs -n1 make test\n" +
			"",
		)
		return
	}

	c := make(chan string)
	quit := make(chan struct{})
	err := make(chan error)

	go cat(c, err, quit)

	for {
		var x string
		shouldPrint := false
		select {
		case x = <-c:
			shouldPrint = true
			if begin {
				shouldPrint = false
				fmt.Println(x)
			}
		case x := <-err:
			fmt.Fprintln(os.Stderr, "reading standard input:", x)
		case <-quit:
			return
		}
		timeout := time.After(time.Duration(timeoutSeconds) * time.Second)
	InnerLoop:
		for {
			select {
			case x = <-c:
				shouldPrint = true
				timeout = time.After(time.Duration(timeoutSeconds) * time.Second)
			case x := <-err:
				fmt.Fprintln(os.Stderr, "reading standard input:", x)
			case <-quit:
				return
			case <-timeout:
				if end && shouldPrint {
					fmt.Println(x)
				}
				break InnerLoop
			}
		}
	}
}
<|endoftext|>