<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/KyleBanks/depth"
)

const (
	outputPadding    = "  "
	outputPrefix     = "├ "
	outputPrefixLast = "└ "
)

var outputJSON bool

type summary struct {
	numInternal int
	numExternal int
	numTesting  int
}

func newSummary() (sum *summary) {
	return &summary{0,0,0}
}

func main() {
	t, pkgs := parse(os.Args[1:])
	if err := handlePkgs(t, pkgs, outputJSON); err != nil {
		os.Exit(1)
	}
}

// parse constructs a depth.Tree from command-line arguments, and returns the
// remaining user-supplied package names
func parse(args []string) (*depth.Tree, []string) {
	f := flag.NewFlagSet(os.Args[0], flag.ExitOnError)

	var t depth.Tree
	f.BoolVar(&t.ResolveInternal, "internal", false, "If set, resolves dependencies of internal (stdlib) packages.")
	f.BoolVar(&t.ResolveTest, "test", false, "If set, resolves dependencies used for testing.")
	f.IntVar(&t.MaxDepth, "max", 0, "Sets the maximum depth of dependencies to resolve.")
	f.BoolVar(&outputJSON, "json", false, "If set, outputs the depencies in JSON format.")
	f.Parse(args)

	return &t, f.Args()
}

// handlePkgs takes a slice of package names, resolves a Tree on them,
// and outputs each Tree to Stdout.
func handlePkgs(t *depth.Tree, pkgs []string, outputJSON bool) error {
	for _, pkg := range pkgs {

		err := t.Resolve(pkg)
		if err != nil {
			fmt.Printf("'%v': FATAL: %v\n", pkg, err)
			return err
		}

		if outputJSON {
			writePkgJSON(os.Stdout, *t.Root)
			continue
		}

		writePkg(os.Stdout, *t.Root, 0, false)
		writePkgSummary(os.Stdout, *t.Root)
	}
	return nil
}

// writePkgSummary
func writePkgSummary(w io.Writer, pkg depth.Pkg) {
	sum := newSummary()
	set := make(map[string]struct{})
	for _, p := range pkg.Deps {
		collectSum(sum, p, set)
	}
	out := fmt.Sprintf("%d dependencies (%d internal, %d external, %d testing).",
	                    sum.numInternal + sum.numExternal,
											sum.numInternal,
											sum.numExternal,
										  sum.numTesting)
	w.Write([]byte(out))
}

func collectSum(sum *summary, pkg depth.Pkg, nameSet map[string]struct{}) {
	if _, ok := nameSet[pkg.Name]; !ok {
		nameSet[pkg.Name] = struct{}{}
		if pkg.Internal {
			sum.numInternal++
		} else {
			sum.numExternal++
		}
		if pkg.Test {
			sum.numTesting++
		}
		for _, p := range pkg.Deps {
			collectSum(sum, p, nameSet)
		}
	}
}

// writePkgJSON writes the full Pkg as JSON to the provided Writer.
func writePkgJSON(w io.Writer, p depth.Pkg) {
	e := json.NewEncoder(w)
	e.SetIndent("", "  ")
	e.Encode(p)
}

// writePkg recursively prints a Pkg and its dependencies to the Writer provided.
func writePkg(w io.Writer, p depth.Pkg, indent int, isLast bool) {
	var prefix string
	if indent > 0 {
		prefix = outputPrefix

		if isLast {
			prefix = outputPrefixLast
		}
	}

	out := fmt.Sprintf("%v%v%v\n", strings.Repeat(outputPadding, indent), prefix, p.String())
	w.Write([]byte(out))

	for idx, d := range p.Deps {
		writePkg(w, d, indent+1, idx == len(p.Deps)-1)
	}
}
<commit_msg>address code review comments; renamed collectSum to collectSummary; added comments, and removed newSummary()<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/KyleBanks/depth"
)

const (
	outputPadding    = "  "
	outputPrefix     = "├ "
	outputPrefixLast = "└ "
)

var outputJSON bool

type summary struct {
	numInternal int
	numExternal int
	numTesting  int
}

func main() {
	t, pkgs := parse(os.Args[1:])
	if err := handlePkgs(t, pkgs, outputJSON); err != nil {
		os.Exit(1)
	}
}

// parse constructs a depth.Tree from command-line arguments, and returns the
// remaining user-supplied package names
func parse(args []string) (*depth.Tree, []string) {
	f := flag.NewFlagSet(os.Args[0], flag.ExitOnError)

	var t depth.Tree
	f.BoolVar(&t.ResolveInternal, "internal", false, "If set, resolves dependencies of internal (stdlib) packages.")
	f.BoolVar(&t.ResolveTest, "test", false, "If set, resolves dependencies used for testing.")
	f.IntVar(&t.MaxDepth, "max", 0, "Sets the maximum depth of dependencies to resolve.")
	f.BoolVar(&outputJSON, "json", false, "If set, outputs the depencies in JSON format.")
	f.Parse(args)

	return &t, f.Args()
}

// handlePkgs takes a slice of package names, resolves a Tree on them,
// and outputs each Tree to Stdout.
func handlePkgs(t *depth.Tree, pkgs []string, outputJSON bool) error {
	for _, pkg := range pkgs {

		err := t.Resolve(pkg)
		if err != nil {
			fmt.Printf("'%v': FATAL: %v\n", pkg, err)
			return err
		}

		if outputJSON {
			writePkgJSON(os.Stdout, *t.Root)
			continue
		}

		writePkg(os.Stdout, *t.Root, 0, false)
		writePkgSummary(os.Stdout, *t.Root)
	}
	return nil
}

// writePkgSummary writes a summary of all packages in a tree
func writePkgSummary(w io.Writer, pkg depth.Pkg) {
	sum := &summary{0,0,0}
	set := make(map[string]struct{})
	for _, p := range pkg.Deps {
		collectSummary(sum, p, set)
	}
	out := fmt.Sprintf("%d dependencies (%d internal, %d external, %d testing).",
	                    sum.numInternal + sum.numExternal,
											sum.numInternal,
											sum.numExternal,
										  sum.numTesting)
	w.Write([]byte(out))
}

func collectSummary(sum *summary, pkg depth.Pkg, nameSet map[string]struct{}) {
	if _, ok := nameSet[pkg.Name]; !ok {
		nameSet[pkg.Name] = struct{}{}
		if pkg.Internal {
			sum.numInternal++
		} else {
			sum.numExternal++
		}
		if pkg.Test {
			sum.numTesting++
		}
		for _, p := range pkg.Deps {
			collectSummary(sum, p, nameSet)
		}
	}
}

// writePkgJSON writes the full Pkg as JSON to the provided Writer.
func writePkgJSON(w io.Writer, p depth.Pkg) {
	e := json.NewEncoder(w)
	e.SetIndent("", "  ")
	e.Encode(p)
}

// writePkg recursively prints a Pkg and its dependencies to the Writer provided.
func writePkg(w io.Writer, p depth.Pkg, indent int, isLast bool) {
	var prefix string
	if indent > 0 {
		prefix = outputPrefix

		if isLast {
			prefix = outputPrefixLast
		}
	}

	out := fmt.Sprintf("%v%v%v\n", strings.Repeat(outputPadding, indent), prefix, p.String())
	w.Write([]byte(out))

	for idx, d := range p.Deps {
		writePkg(w, d, indent+1, idx == len(p.Deps)-1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"

	"github.com/belogik/goes"
)

func main() {

	host := flag.String("host", "localhost", "elasticsearch host")
	port := flag.String("port", "9200", "elasticsearch port")

	flag.Parse()

	conn := goes.NewConnection(*host, *port)
	fmt.Println(conn)

}
<commit_msg>can display 10 items<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"net/url"
	"strings"

	"github.com/belogik/goes"
)

func main() {

	host := flag.String("host", "localhost", "elasticsearch host")
	port := flag.String("port", "9200", "elasticsearch port")
	indicesString := flag.String("indices", "", "indices to search (or all)")
	fieldsString := flag.String("f", "content.245.a", "field or fields space separated")

	flag.Parse()

	var indices []string
	trimmed := strings.TrimSpace(*indicesString)
	if len(trimmed) > 0 {
		indices = strings.Fields(trimmed)
	}

	fields := strings.Fields(*fieldsString)
	conn := goes.NewConnection(*host, *port)
	var query = map[string]interface{}{
		"query": map[string]interface{}{
			"match_all": map[string]interface{}{},
		},
		"fields": fields,
	}

	extraArgs := make(url.Values, 1)
	searchResults, err := conn.Search(query, indices, []string{""}, extraArgs)
	if err != nil {
		log.Fatalln(err)
	}
	for _, hit := range searchResults.Hits.Hits {
		var columns []string
		for _, f := range fields {
			switch value := hit.Fields[f].(type) {
			case []interface{}:
				var c []string
				for _, e := range value {
					c = append(c, e.(string))
				}
				columns = append(columns, strings.Join(c, "|"))
			default:
				log.Fatal("unknown field type in response")
			}
		}
		fmt.Println(strings.Join(columns, "\t"))
	}

}
<|endoftext|>


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

package main

import (
	"flag"
	"github.com/couchbase/gometa/server"
	"log"
	"os"
)

//
// main function
//
func main() {
	var isClient bool
	var isWatcher bool
	var config string

	flag.BoolVar(&isClient, "client", false, "run as test client")
	flag.BoolVar(&isWatcher, "watcher", false, "run as watcher")
	flag.StringVar(&config, "config", "", "path for configuration file")
	flag.Parse()

	if isClient {
		runTestClient(config)
		os.Exit(0)
	}

	if isWatcher {
		runWatcher(config)
		os.Exit(0)
	}

	err := server.RunServer(config)
	if err != nil {
		log.Printf("Encounter Error = %s. Terminate server", err.Error())
		os.Exit(1)
	}

	os.Exit(0)
}
<commit_msg>Allow terminating gometa on EOL or EOF on standard input.<commit_after>// @author Couchbase <info@couchbase.com>
// @copyright 2014 Couchbase, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"flag"
	"github.com/couchbase/gometa/server"
	"log"
	"os"
)

func stdinWatcher() {
	b := make([]byte, 1)

	for {
		_, err := os.Stdin.Read(b)
		if err != nil {
			log.Printf("Got %s when reading stdin. Terminating.", err.Error())
			break
		}

		if b[0] == '\n' || b[0] == '\r' {
			log.Printf("Got new line on a stdin. Terminating.")
			break
		}
	}

	os.Exit(0)
}

//
// main function
//
func main() {
	var isClient bool
	var isWatcher bool
	var config string
	var watchStdin bool

	flag.BoolVar(&isClient, "client", false, "run as test client")
	flag.BoolVar(&isWatcher, "watcher", false, "run as watcher")
	flag.StringVar(&config, "config", "", "path for configuration file")
	flag.BoolVar(&watchStdin, "watch-stdin", true,
		"watch standard input and terminate on EOL or EOF")
	flag.Parse()

	if isClient {
		runTestClient(config)
		os.Exit(0)
	}

	if isWatcher {
		runWatcher(config)
		os.Exit(0)
	}

	if watchStdin {
		go stdinWatcher()
	}

	err := server.RunServer(config)
	if err != nil {
		log.Printf("Encounter Error = %s. Terminate server", err.Error())
		os.Exit(1)
	}

	os.Exit(0)
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"flag"
	"github.com/htcat/htcat"
	"log"
	"net/http"
	"net/url"
	"os"
	"runtime"
)

const version = "1.0.0"

var onlyPrintVersion = flag.Bool("version", false, "print the htcat version")

const (
	_        = iota
	KB int64 = 1 << (10 * iota)
	MB
	GB
	TB
	PB
	EB
)

func printUsage() {
	log.Printf("usage: %v URL", os.Args[0])
}

func main() {
	flag.Parse()
	args := flag.Args()

	if *onlyPrintVersion {
		os.Stdout.Write([]byte(version + "\n"))
		os.Exit(0)
	}

	if len(args) != 1 {
		printUsage()
		log.Fatalf("aborting: incorrect usage")
	}

	u, err := url.Parse(args[0])
	if err != nil {
		log.Fatalf("aborting: could not parse given URL: %v", err)
	}

	client := *http.DefaultClient

	// Only support HTTP and HTTPS schemes
	switch u.Scheme {
	case "https":
		client.Transport = &http.Transport{
			TLSClientConfig: &tls.Config{},
		}
	case "http":
	default:
		// This error path can be hit with common alphanumeric
		// lexemes like "help", which also parse as URLs,
		// which makes this error message somewhat
		// incomprehensible.  Try to help out a user by
		// printing the usage here.
		printUsage()
		log.Fatalf("aborting: unsupported URL scheme %v", u.Scheme)
	}

	// On fast links (~= saturating gigabit), parallel execution
	// gives a large speedup.
	runtime.GOMAXPROCS(runtime.NumCPU())

	// Begin the GET.
	htc := htcat.New(&client, u, 5)

	if _, err := htc.WriteTo(os.Stdout); err != nil {
		log.Fatalf("aborting: could not write to output stream: %v",
			err)
	}
}
<commit_msg>v1.0.1<commit_after>package main

import (
	"crypto/tls"
	"flag"
	"github.com/htcat/htcat"
	"log"
	"net/http"
	"net/url"
	"os"
	"runtime"
)

const version = "1.0.1"

var onlyPrintVersion = flag.Bool("version", false, "print the htcat version")

const (
	_        = iota
	KB int64 = 1 << (10 * iota)
	MB
	GB
	TB
	PB
	EB
)

func printUsage() {
	log.Printf("usage: %v URL", os.Args[0])
}

func main() {
	flag.Parse()
	args := flag.Args()

	if *onlyPrintVersion {
		os.Stdout.Write([]byte(version + "\n"))
		os.Exit(0)
	}

	if len(args) != 1 {
		printUsage()
		log.Fatalf("aborting: incorrect usage")
	}

	u, err := url.Parse(args[0])
	if err != nil {
		log.Fatalf("aborting: could not parse given URL: %v", err)
	}

	client := *http.DefaultClient

	// Only support HTTP and HTTPS schemes
	switch u.Scheme {
	case "https":
		client.Transport = &http.Transport{
			TLSClientConfig: &tls.Config{},
		}
	case "http":
	default:
		// This error path can be hit with common alphanumeric
		// lexemes like "help", which also parse as URLs,
		// which makes this error message somewhat
		// incomprehensible.  Try to help out a user by
		// printing the usage here.
		printUsage()
		log.Fatalf("aborting: unsupported URL scheme %v", u.Scheme)
	}

	// On fast links (~= saturating gigabit), parallel execution
	// gives a large speedup.
	runtime.GOMAXPROCS(runtime.NumCPU())

	// Begin the GET.
	htc := htcat.New(&client, u, 5)

	if _, err := htc.WriteTo(os.Stdout); err != nil {
		log.Fatalf("aborting: could not write to output stream: %v",
			err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"strconv"
)

var ipfsFileDescNum = uint64(1024)

func init() {
	if val := os.Getenv("IPFS_FD_MAX"); val != "" {
		n, err := strconv.Atoi(val)
		if err != nil {
			log.Errorf("bad value for IPFS_FD_MAX: %s", err)
		} else {
			ipfsFileDescNum = uint64(n)
		}
	}
}
<commit_msg>Bump default ulimit to 2048<commit_after>package main

import (
	"os"
	"strconv"
)

var ipfsFileDescNum = uint64(2048)

func init() {
	if val := os.Getenv("IPFS_FD_MAX"); val != "" {
		n, err := strconv.Atoi(val)
		if err != nil {
			log.Errorf("bad value for IPFS_FD_MAX: %s", err)
		} else {
			ipfsFileDescNum = uint64(n)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"regexp"
	"runtime"
	"sort"
	"strconv"
	"time"

	"github.com/go-errors/errors"
	isatty "github.com/mattn/go-isatty"
	lua "github.com/yuin/gopher-lua"
	"github.com/zyedidia/micro/v2/internal/action"
	"github.com/zyedidia/micro/v2/internal/buffer"
	"github.com/zyedidia/micro/v2/internal/clipboard"
	"github.com/zyedidia/micro/v2/internal/config"
	ulua "github.com/zyedidia/micro/v2/internal/lua"
	"github.com/zyedidia/micro/v2/internal/screen"
	"github.com/zyedidia/micro/v2/internal/shell"
	"github.com/zyedidia/micro/v2/internal/util"
	"github.com/zyedidia/tcell"
)

var (
	// Event channel
	autosave chan bool

	// Command line flags
	flagVersion   = flag.Bool("version", false, "Show the version number and information")
	flagConfigDir = flag.String("config-dir", "", "Specify a custom location for the configuration directory")
	flagOptions   = flag.Bool("options", false, "Show all option help")
	flagDebug     = flag.Bool("debug", false, "Enable debug mode (prints debug info to ./log.txt)")
	flagPlugin    = flag.String("plugin", "", "Plugin command")
	flagClean     = flag.Bool("clean", false, "Clean configuration directory")
	optionFlags   map[string]*string
)

func InitFlags() {
	flag.Usage = func() {
		fmt.Println("Usage: micro [OPTIONS] [FILE]...")
		fmt.Println("-clean")
		fmt.Println("    \tCleans the configuration directory")
		fmt.Println("-config-dir dir")
		fmt.Println("    \tSpecify a custom location for the configuration directory")
		fmt.Println("[FILE]:LINE:COL (if the `parsecursor` option is enabled)")
		fmt.Println("+LINE:COL")
		fmt.Println("    \tSpecify a line and column to start the cursor at when opening a buffer")
		fmt.Println("-options")
		fmt.Println("    \tShow all option help")
		fmt.Println("-debug")
		fmt.Println("    \tEnable debug mode (enables logging to ./log.txt)")
		fmt.Println("-version")
		fmt.Println("    \tShow the version number and information")

		fmt.Print("\nMicro's plugin's can be managed at the command line with the following commands.\n")
		fmt.Println("-plugin install [PLUGIN]...")
		fmt.Println("    \tInstall plugin(s)")
		fmt.Println("-plugin remove [PLUGIN]...")
		fmt.Println("    \tRemove plugin(s)")
		fmt.Println("-plugin update [PLUGIN]...")
		fmt.Println("    \tUpdate plugin(s) (if no argument is given, updates all plugins)")
		fmt.Println("-plugin search [PLUGIN]...")
		fmt.Println("    \tSearch for a plugin")
		fmt.Println("-plugin list")
		fmt.Println("    \tList installed plugins")
		fmt.Println("-plugin available")
		fmt.Println("    \tList available plugins")

		fmt.Print("\nMicro's options can also be set via command line arguments for quick\nadjustments. For real configuration, please use the settings.json\nfile (see 'help options').\n\n")
		fmt.Println("-option value")
		fmt.Println("    \tSet `option` to `value` for this session")
		fmt.Println("    \tFor example: `micro -syntax off file.c`")
		fmt.Println("\nUse `micro -options` to see the full list of configuration options")
	}

	optionFlags = make(map[string]*string)

	for k, v := range config.DefaultAllSettings() {
		optionFlags[k] = flag.String(k, "", fmt.Sprintf("The %s option. Default value: '%v'.", k, v))
	}

	flag.Parse()

	if *flagVersion {
		// If -version was passed
		fmt.Println("Version:", util.Version)
		fmt.Println("Commit hash:", util.CommitHash)
		fmt.Println("Compiled on", util.CompileDate)
		os.Exit(0)
	}

	if *flagOptions {
		// If -options was passed
		var keys []string
		m := config.DefaultAllSettings()
		for k := range m {
			keys = append(keys, k)
		}
		sort.Strings(keys)
		for _, k := range keys {
			v := m[k]
			fmt.Printf("-%s value\n", k)
			fmt.Printf("    \tDefault value: '%v'\n", v)
		}
		os.Exit(0)
	}

	if util.Debug == "OFF" && *flagDebug {
		util.Debug = "ON"
	}
}

// DoPluginFlags parses and executes any flags that require LoadAllPlugins (-plugin and -clean)
func DoPluginFlags() {
	if *flagClean || *flagPlugin != "" {
		config.LoadAllPlugins()

		if *flagPlugin != "" {
			args := flag.Args()

			config.PluginCommand(os.Stdout, *flagPlugin, args)
		} else if *flagClean {
			CleanConfig()
		}

		os.Exit(0)
	}
}

// LoadInput determines which files should be loaded into buffers
// based on the input stored in flag.Args()
func LoadInput(args []string) []*buffer.Buffer {
	// There are a number of ways micro should start given its input

	// 1. If it is given a files in flag.Args(), it should open those

	// 2. If there is no input file and the input is not a terminal, that means
	// something is being piped in and the stdin should be opened in an
	// empty buffer

	// 3. If there is no input file and the input is a terminal, an empty buffer
	// should be opened

	var filename string
	var input []byte
	var err error
	buffers := make([]*buffer.Buffer, 0, len(args))

	btype := buffer.BTDefault
	if !isatty.IsTerminal(os.Stdout.Fd()) {
		btype = buffer.BTStdout
	}

	files := make([]string, 0, len(args))
	flagStartPos := buffer.Loc{-1, -1}
	flagr := regexp.MustCompile(`^\+(\d+)(?::(\d+))?$`)
	for _, a := range args {
		match := flagr.FindStringSubmatch(a)
		if len(match) == 3 && match[2] != "" {
			line, err := strconv.Atoi(match[1])
			if err != nil {
				screen.TermMessage(err)
				continue
			}
			col, err := strconv.Atoi(match[2])
			if err != nil {
				screen.TermMessage(err)
				continue
			}
			flagStartPos = buffer.Loc{col - 1, line - 1}
		} else if len(match) == 3 && match[2] == "" {
			line, err := strconv.Atoi(match[1])
			if err != nil {
				screen.TermMessage(err)
				continue
			}
			flagStartPos = buffer.Loc{0, line - 1}
		} else {
			files = append(files, a)
		}
	}

	if len(files) > 0 {
		// Option 1
		// We go through each file and load it
		for i := 0; i < len(files); i++ {
			buf, err := buffer.NewBufferFromFileAtLoc(files[i], btype, flagStartPos)
			if err != nil {
				screen.TermMessage(err)
				continue
			}
			// If the file didn't exist, input will be empty, and we'll open an empty buffer
			buffers = append(buffers, buf)
		}
	} else if !isatty.IsTerminal(os.Stdin.Fd()) {
		// Option 2
		// The input is not a terminal, so something is being piped in
		// and we should read from stdin
		input, err = ioutil.ReadAll(os.Stdin)
		if err != nil {
			screen.TermMessage("Error reading from stdin: ", err)
			input = []byte{}
		}
		buffers = append(buffers, buffer.NewBufferFromStringAtLoc(string(input), filename, btype, flagStartPos))
	} else {
		// Option 3, just open an empty buffer
		buffers = append(buffers, buffer.NewBufferFromStringAtLoc(string(input), filename, btype, flagStartPos))
	}

	return buffers
}

func main() {
	defer func() {
		if util.Stdout.Len() > 0 {
			fmt.Fprint(os.Stdout, util.Stdout.String())
		}
		os.Exit(0)
	}()

	// runtime.SetCPUProfileRate(400)
	// f, _ := os.Create("micro.prof")
	// pprof.StartCPUProfile(f)
	// defer pprof.StopCPUProfile()

	var err error

	InitFlags()

	InitLog()

	err = config.InitConfigDir(*flagConfigDir)
	if err != nil {
		screen.TermMessage(err)
	}

	config.InitRuntimeFiles()
	err = config.ReadSettings()
	if err != nil {
		screen.TermMessage(err)
	}
	err = config.InitGlobalSettings()
	if err != nil {
		screen.TermMessage(err)
	}

	// flag options
	for k, v := range optionFlags {
		if *v != "" {
			nativeValue, err := config.GetNativeValue(k, config.DefaultAllSettings()[k], *v)
			if err != nil {
				screen.TermMessage(err)
				continue
			}
			config.GlobalSettings[k] = nativeValue
		}
	}

	DoPluginFlags()

	err = screen.Init()
	if err != nil {
		fmt.Println(err)
		fmt.Println("Fatal: Micro could not initialize a Screen.")
		os.Exit(1)
	}

	m := clipboard.SetMethod(config.GetGlobalOption("clipboard").(string))
	clipErr := clipboard.Initialize(m)

	defer func() {
		if err := recover(); err != nil {
			screen.Screen.Fini()
			fmt.Println("Micro encountered an error:", err)
			// backup all open buffers
			for _, b := range buffer.OpenBuffers {
				b.Backup()
			}
			// Print the stack trace too
			fmt.Print(errors.Wrap(err, 2).ErrorStack())
			os.Exit(1)
		}
	}()

	err = config.LoadAllPlugins()
	if err != nil {
		screen.TermMessage(err)
	}

	action.InitBindings()
	action.InitCommands()

	err = config.InitColorscheme()
	if err != nil {
		screen.TermMessage(err)
	}

	err = config.RunPluginFn("preinit")
	if err != nil {
		screen.TermMessage(err)
	}

	args := flag.Args()
	b := LoadInput(args)

	if len(b) == 0 {
		// No buffers to open
		screen.Screen.Fini()
		runtime.Goexit()
	}

	action.InitTabs(b)
	action.InitGlobals()

	err = config.RunPluginFn("init")
	if err != nil {
		screen.TermMessage(err)
	}

	err = config.RunPluginFn("postinit")
	if err != nil {
		screen.TermMessage(err)
	}

	if clipErr != nil {
		action.InfoBar.Error(clipErr, " or change 'clipboard' option")
	}

	screen.Events = make(chan tcell.Event)

	// Here is the event loop which runs in a separate thread
	go func() {
		for {
			screen.Lock()
			e := screen.Screen.PollEvent()
			screen.Unlock()
			if e != nil {
				screen.Events <- e
			}
		}
	}()

	// clear the drawchan so we don't redraw excessively
	// if someone requested a redraw before we started displaying
	for len(screen.DrawChan()) > 0 {
		<-screen.DrawChan()
	}

	// wait for initial resize event
	select {
	case event := <-screen.Events:
		action.Tabs.HandleEvent(event)
	case <-time.After(10 * time.Millisecond):
		// time out after 10ms
	}

	// Since this loop is very slow (waits for user input every time) it's
	// okay to be inefficient and run it via a function every time
	// We do this so we can recover from panics without crashing the editor
	for {
		DoEvent()
	}
}

// DoEvent runs the main action loop of the editor
func DoEvent() {
	var event tcell.Event

	// recover from errors without crashing the editor
	defer func() {
		if err := recover(); err != nil {
			if e, ok := err.(*lua.ApiError); ok {
				screen.TermMessage("Lua API error:", e)
			} else {
				screen.TermMessage("Micro encountered an error:", errors.Wrap(err, 2).ErrorStack(), "\nIf you can reproduce this error, please report it at https://github.com/zyedidia/micro/issues")
			}
		}
	}()
	// Display everything
	screen.Screen.Fill(' ', config.DefStyle)
	screen.Screen.HideCursor()
	action.Tabs.Display()
	for _, ep := range action.MainTab().Panes {
		ep.Display()
	}
	action.MainTab().Display()
	action.InfoBar.Display()
	screen.Screen.Show()

	// Check for new events
	select {
	case f := <-shell.Jobs:
		// If a new job has finished while running in the background we should execute the callback
		ulua.Lock.Lock()
		f.Function(f.Output, f.Args)
		ulua.Lock.Unlock()
	case <-config.Autosave:
		ulua.Lock.Lock()
		for _, b := range buffer.OpenBuffers {
			b.Save()
		}
		ulua.Lock.Unlock()
	case <-shell.CloseTerms:
	case event = <-screen.Events:
	case <-screen.DrawChan():
		for len(screen.DrawChan()) > 0 {
			<-screen.DrawChan()
		}
	}

	ulua.Lock.Lock()
	if action.InfoBar.HasPrompt {
		action.InfoBar.HandleEvent(event)
	} else {
		action.Tabs.HandleEvent(event)
	}
	ulua.Lock.Unlock()
}
<commit_msg>Exit gracefully when SIGTERM is received<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/signal"
	"regexp"
	"runtime"
	"sort"
	"strconv"
	"syscall"
	"time"

	"github.com/go-errors/errors"
	isatty "github.com/mattn/go-isatty"
	lua "github.com/yuin/gopher-lua"
	"github.com/zyedidia/micro/v2/internal/action"
	"github.com/zyedidia/micro/v2/internal/buffer"
	"github.com/zyedidia/micro/v2/internal/clipboard"
	"github.com/zyedidia/micro/v2/internal/config"
	ulua "github.com/zyedidia/micro/v2/internal/lua"
	"github.com/zyedidia/micro/v2/internal/screen"
	"github.com/zyedidia/micro/v2/internal/shell"
	"github.com/zyedidia/micro/v2/internal/util"
	"github.com/zyedidia/tcell"
)

var (
	// Event channel
	autosave chan bool

	// Command line flags
	flagVersion   = flag.Bool("version", false, "Show the version number and information")
	flagConfigDir = flag.String("config-dir", "", "Specify a custom location for the configuration directory")
	flagOptions   = flag.Bool("options", false, "Show all option help")
	flagDebug     = flag.Bool("debug", false, "Enable debug mode (prints debug info to ./log.txt)")
	flagPlugin    = flag.String("plugin", "", "Plugin command")
	flagClean     = flag.Bool("clean", false, "Clean configuration directory")
	optionFlags   map[string]*string
)

func InitFlags() {
	flag.Usage = func() {
		fmt.Println("Usage: micro [OPTIONS] [FILE]...")
		fmt.Println("-clean")
		fmt.Println("    \tCleans the configuration directory")
		fmt.Println("-config-dir dir")
		fmt.Println("    \tSpecify a custom location for the configuration directory")
		fmt.Println("[FILE]:LINE:COL (if the `parsecursor` option is enabled)")
		fmt.Println("+LINE:COL")
		fmt.Println("    \tSpecify a line and column to start the cursor at when opening a buffer")
		fmt.Println("-options")
		fmt.Println("    \tShow all option help")
		fmt.Println("-debug")
		fmt.Println("    \tEnable debug mode (enables logging to ./log.txt)")
		fmt.Println("-version")
		fmt.Println("    \tShow the version number and information")

		fmt.Print("\nMicro's plugin's can be managed at the command line with the following commands.\n")
		fmt.Println("-plugin install [PLUGIN]...")
		fmt.Println("    \tInstall plugin(s)")
		fmt.Println("-plugin remove [PLUGIN]...")
		fmt.Println("    \tRemove plugin(s)")
		fmt.Println("-plugin update [PLUGIN]...")
		fmt.Println("    \tUpdate plugin(s) (if no argument is given, updates all plugins)")
		fmt.Println("-plugin search [PLUGIN]...")
		fmt.Println("    \tSearch for a plugin")
		fmt.Println("-plugin list")
		fmt.Println("    \tList installed plugins")
		fmt.Println("-plugin available")
		fmt.Println("    \tList available plugins")

		fmt.Print("\nMicro's options can also be set via command line arguments for quick\nadjustments. For real configuration, please use the settings.json\nfile (see 'help options').\n\n")
		fmt.Println("-option value")
		fmt.Println("    \tSet `option` to `value` for this session")
		fmt.Println("    \tFor example: `micro -syntax off file.c`")
		fmt.Println("\nUse `micro -options` to see the full list of configuration options")
	}

	optionFlags = make(map[string]*string)

	for k, v := range config.DefaultAllSettings() {
		optionFlags[k] = flag.String(k, "", fmt.Sprintf("The %s option. Default value: '%v'.", k, v))
	}

	flag.Parse()

	if *flagVersion {
		// If -version was passed
		fmt.Println("Version:", util.Version)
		fmt.Println("Commit hash:", util.CommitHash)
		fmt.Println("Compiled on", util.CompileDate)
		os.Exit(0)
	}

	if *flagOptions {
		// If -options was passed
		var keys []string
		m := config.DefaultAllSettings()
		for k := range m {
			keys = append(keys, k)
		}
		sort.Strings(keys)
		for _, k := range keys {
			v := m[k]
			fmt.Printf("-%s value\n", k)
			fmt.Printf("    \tDefault value: '%v'\n", v)
		}
		os.Exit(0)
	}

	if util.Debug == "OFF" && *flagDebug {
		util.Debug = "ON"
	}
}

// DoPluginFlags parses and executes any flags that require LoadAllPlugins (-plugin and -clean)
func DoPluginFlags() {
	if *flagClean || *flagPlugin != "" {
		config.LoadAllPlugins()

		if *flagPlugin != "" {
			args := flag.Args()

			config.PluginCommand(os.Stdout, *flagPlugin, args)
		} else if *flagClean {
			CleanConfig()
		}

		os.Exit(0)
	}
}

// LoadInput determines which files should be loaded into buffers
// based on the input stored in flag.Args()
func LoadInput(args []string) []*buffer.Buffer {
	// There are a number of ways micro should start given its input

	// 1. If it is given a files in flag.Args(), it should open those

	// 2. If there is no input file and the input is not a terminal, that means
	// something is being piped in and the stdin should be opened in an
	// empty buffer

	// 3. If there is no input file and the input is a terminal, an empty buffer
	// should be opened

	var filename string
	var input []byte
	var err error
	buffers := make([]*buffer.Buffer, 0, len(args))

	btype := buffer.BTDefault
	if !isatty.IsTerminal(os.Stdout.Fd()) {
		btype = buffer.BTStdout
	}

	files := make([]string, 0, len(args))
	flagStartPos := buffer.Loc{-1, -1}
	flagr := regexp.MustCompile(`^\+(\d+)(?::(\d+))?$`)
	for _, a := range args {
		match := flagr.FindStringSubmatch(a)
		if len(match) == 3 && match[2] != "" {
			line, err := strconv.Atoi(match[1])
			if err != nil {
				screen.TermMessage(err)
				continue
			}
			col, err := strconv.Atoi(match[2])
			if err != nil {
				screen.TermMessage(err)
				continue
			}
			flagStartPos = buffer.Loc{col - 1, line - 1}
		} else if len(match) == 3 && match[2] == "" {
			line, err := strconv.Atoi(match[1])
			if err != nil {
				screen.TermMessage(err)
				continue
			}
			flagStartPos = buffer.Loc{0, line - 1}
		} else {
			files = append(files, a)
		}
	}

	if len(files) > 0 {
		// Option 1
		// We go through each file and load it
		for i := 0; i < len(files); i++ {
			buf, err := buffer.NewBufferFromFileAtLoc(files[i], btype, flagStartPos)
			if err != nil {
				screen.TermMessage(err)
				continue
			}
			// If the file didn't exist, input will be empty, and we'll open an empty buffer
			buffers = append(buffers, buf)
		}
	} else if !isatty.IsTerminal(os.Stdin.Fd()) {
		// Option 2
		// The input is not a terminal, so something is being piped in
		// and we should read from stdin
		input, err = ioutil.ReadAll(os.Stdin)
		if err != nil {
			screen.TermMessage("Error reading from stdin: ", err)
			input = []byte{}
		}
		buffers = append(buffers, buffer.NewBufferFromStringAtLoc(string(input), filename, btype, flagStartPos))
	} else {
		// Option 3, just open an empty buffer
		buffers = append(buffers, buffer.NewBufferFromStringAtLoc(string(input), filename, btype, flagStartPos))
	}

	return buffers
}

func main() {
	defer func() {
		if util.Stdout.Len() > 0 {
			fmt.Fprint(os.Stdout, util.Stdout.String())
		}
		os.Exit(0)
	}()

	// runtime.SetCPUProfileRate(400)
	// f, _ := os.Create("micro.prof")
	// pprof.StartCPUProfile(f)
	// defer pprof.StopCPUProfile()

	var err error

	InitFlags()

	InitLog()

	err = config.InitConfigDir(*flagConfigDir)
	if err != nil {
		screen.TermMessage(err)
	}

	config.InitRuntimeFiles()
	err = config.ReadSettings()
	if err != nil {
		screen.TermMessage(err)
	}
	err = config.InitGlobalSettings()
	if err != nil {
		screen.TermMessage(err)
	}

	// flag options
	for k, v := range optionFlags {
		if *v != "" {
			nativeValue, err := config.GetNativeValue(k, config.DefaultAllSettings()[k], *v)
			if err != nil {
				screen.TermMessage(err)
				continue
			}
			config.GlobalSettings[k] = nativeValue
		}
	}

	DoPluginFlags()

	err = screen.Init()
	if err != nil {
		fmt.Println(err)
		fmt.Println("Fatal: Micro could not initialize a Screen.")
		os.Exit(1)
	}

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Kill, syscall.SIGTERM)

	go func() {
		<-c
		if screen.Screen != nil {
			screen.Screen.Fini()
		}
		os.Exit(0)
	}()

	m := clipboard.SetMethod(config.GetGlobalOption("clipboard").(string))
	clipErr := clipboard.Initialize(m)

	defer func() {
		if err := recover(); err != nil {
			if screen.Screen != nil {
				screen.Screen.Fini()
			}
			fmt.Println("Micro encountered an error:", err)
			// backup all open buffers
			for _, b := range buffer.OpenBuffers {
				b.Backup()
			}
			// Print the stack trace too
			fmt.Print(errors.Wrap(err, 2).ErrorStack())
			os.Exit(1)
		}
	}()

	err = config.LoadAllPlugins()
	if err != nil {
		screen.TermMessage(err)
	}

	action.InitBindings()
	action.InitCommands()

	err = config.InitColorscheme()
	if err != nil {
		screen.TermMessage(err)
	}

	err = config.RunPluginFn("preinit")
	if err != nil {
		screen.TermMessage(err)
	}

	args := flag.Args()
	b := LoadInput(args)

	if len(b) == 0 {
		// No buffers to open
		screen.Screen.Fini()
		runtime.Goexit()
	}

	action.InitTabs(b)
	action.InitGlobals()

	err = config.RunPluginFn("init")
	if err != nil {
		screen.TermMessage(err)
	}

	err = config.RunPluginFn("postinit")
	if err != nil {
		screen.TermMessage(err)
	}

	if clipErr != nil {
		action.InfoBar.Error(clipErr, " or change 'clipboard' option")
	}

	screen.Events = make(chan tcell.Event)

	// Here is the event loop which runs in a separate thread
	go func() {
		for {
			screen.Lock()
			e := screen.Screen.PollEvent()
			screen.Unlock()
			if e != nil {
				screen.Events <- e
			}
		}
	}()

	// clear the drawchan so we don't redraw excessively
	// if someone requested a redraw before we started displaying
	for len(screen.DrawChan()) > 0 {
		<-screen.DrawChan()
	}

	// wait for initial resize event
	select {
	case event := <-screen.Events:
		action.Tabs.HandleEvent(event)
	case <-time.After(10 * time.Millisecond):
		// time out after 10ms
	}

	// Since this loop is very slow (waits for user input every time) it's
	// okay to be inefficient and run it via a function every time
	// We do this so we can recover from panics without crashing the editor
	for {
		DoEvent()
	}
}

// DoEvent runs the main action loop of the editor
func DoEvent() {
	var event tcell.Event

	// recover from errors without crashing the editor
	defer func() {
		if err := recover(); err != nil {
			if e, ok := err.(*lua.ApiError); ok {
				screen.TermMessage("Lua API error:", e)
			} else {
				screen.TermMessage("Micro encountered an error:", errors.Wrap(err, 2).ErrorStack(), "\nIf you can reproduce this error, please report it at https://github.com/zyedidia/micro/issues")
			}
		}
	}()
	// Display everything
	screen.Screen.Fill(' ', config.DefStyle)
	screen.Screen.HideCursor()
	action.Tabs.Display()
	for _, ep := range action.MainTab().Panes {
		ep.Display()
	}
	action.MainTab().Display()
	action.InfoBar.Display()
	screen.Screen.Show()

	// Check for new events
	select {
	case f := <-shell.Jobs:
		// If a new job has finished while running in the background we should execute the callback
		ulua.Lock.Lock()
		f.Function(f.Output, f.Args)
		ulua.Lock.Unlock()
	case <-config.Autosave:
		ulua.Lock.Lock()
		for _, b := range buffer.OpenBuffers {
			b.Save()
		}
		ulua.Lock.Unlock()
	case <-shell.CloseTerms:
	case event = <-screen.Events:
	case <-screen.DrawChan():
		for len(screen.DrawChan()) > 0 {
			<-screen.DrawChan()
		}
	}

	ulua.Lock.Lock()
	if action.InfoBar.HasPrompt {
		action.InfoBar.HandleEvent(event)
	} else {
		action.Tabs.HandleEvent(event)
	}
	ulua.Lock.Unlock()
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package main

import (
	"flag"
	"fmt"
	"os"
	"runtime"

	"github.com/golang/glog"
	"github.com/spf13/pflag"

	apiv1 "k8s.io/api/core/v1"

	"k8s.io/ingress-nginx/internal/ingress/annotations/class"
	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
	"k8s.io/ingress-nginx/internal/ingress/controller"
	ngx_config "k8s.io/ingress-nginx/internal/ingress/controller/config"
	ing_net "k8s.io/ingress-nginx/internal/net"
)

func parseFlags() (bool, *controller.Configuration, error) {
	var (
		flags = pflag.NewFlagSet("", pflag.ExitOnError)

		apiserverHost = flags.String("apiserver-host", "",
			`Address of the Kubernetes API server.
Takes the form "protocol://address:port". If not specified, it is assumed the
program runs inside a Kubernetes cluster and local discovery is attempted.`)

		kubeConfigFile = flags.String("kubeconfig", "",
			`Path to a kubeconfig file containing authorization and API server information.`)

		defaultSvc = flags.String("default-backend-service", "",
			`Service used to serve HTTP requests not matching any known server name (catch-all).
Takes the form "namespace/name". The controller configures NGINX to forward
requests to the first port of this Service.`)

		ingressClass = flags.String("ingress-class", "",
			`Name of the ingress class this controller satisfies.
The class of an Ingress object is set using the annotation "kubernetes.io/ingress.class".
All ingress classes are satisfied if this parameter is left empty.`)

		configMap = flags.String("configmap", "",
			`Name of the ConfigMap containing custom global configurations for the controller.`)

		publishSvc = flags.String("publish-service", "",
			`Service fronting the Ingress controller.
Takes the form "namespace/name". When used together with update-status, the
controller mirrors the address of this service's endpoints to the load-balancer
status of all Ingress objects it satisfies.`)

		tcpConfigMapName = flags.String("tcp-services-configmap", "",
			`Name of the ConfigMap containing the definition of the TCP services to expose.
The key in the map indicates the external port to be used. The value is a
reference to a Service in the form "namespace/name:port", where "port" can
either be a port number or name. TCP ports 80 and 443 are reserved by the
controller for servicing HTTP traffic.`)

		udpConfigMapName = flags.String("udp-services-configmap", "",
			`Name of the ConfigMap containing the definition of the UDP services to expose.
The key in the map indicates the external port to be used. The value is a
reference to a Service in the form "namespace/name:port", where "port" can
either be a port name or number.`)

		resyncPeriod = flags.Duration("sync-period", 0,
			`Period at which the controller forces the repopulation of its local object stores. Disabled by default.`)

		watchNamespace = flags.String("watch-namespace", apiv1.NamespaceAll,
			`Namespace the controller watches for updates to Kubernetes objects.
This includes Ingresses, Services and all configuration resources. All
namespaces are watched if this parameter is left empty.`)

		profiling = flags.Bool("profiling", true,
			`Enable profiling via web interface host:port/debug/pprof/`)

		defSSLCertificate = flags.String("default-ssl-certificate", "",
			`Secret containing a SSL certificate to be used by the default HTTPS server (catch-all).
Takes the form "namespace/name".`)

		defHealthzURL = flags.String("health-check-path", "/healthz",
			`URL path of the health check endpoint.
Configured inside the NGINX status server. All requests received on the port
defined by the healthz-port parameter are forwarded internally to this path.`)

		updateStatus = flags.Bool("update-status", true,
			`Update the load-balancer status of Ingress objects this controller satisfies.
Requires setting the publish-service parameter to a valid Service reference.`)

		electionID = flags.String("election-id", "ingress-controller-leader",
			`Election id to use for Ingress status updates.`)

		forceIsolation = flags.Bool("force-namespace-isolation", false,
			`Force namespace isolation.
Prevents Ingress objects from referencing Secrets and ConfigMaps located in a
different namespace than their own. May be used together with watch-namespace.`)

		updateStatusOnShutdown = flags.Bool("update-status-on-shutdown", true,
			`Update the load-balancer status of Ingress objects when the controller shuts down.
Requires the update-status parameter.`)

		sortBackends = flags.Bool("sort-backends", false,
			`Sort servers inside NGINX upstreams.`)

		useNodeInternalIP = flags.Bool("report-node-internal-ip-address", false,
			`Set the load-balancer status of Ingress objects to internal Node addresses instead of external.
Requires the update-status parameter.`)

		showVersion = flags.Bool("version", false,
			`Show release information about the NGINX Ingress controller and exit.`)

		enableSSLPassthrough = flags.Bool("enable-ssl-passthrough", false,
			`Enable SSL Passthrough.`)

		annotationsPrefix = flags.String("annotations-prefix", "nginx.ingress.kubernetes.io",
			`Prefix of the Ingress annotations specific to the NGINX controller.`)

		enableSSLChainCompletion = flags.Bool("enable-ssl-chain-completion", true,
			`Autocomplete SSL certificate chains with missing intermediate CA certificates.
A valid certificate chain is required to enable OCSP stapling. Certificates
uploaded to Kubernetes must have the "Authority Information Access" X.509 v3
extension for this to succeed.`)

		syncRateLimit = flags.Float32("sync-rate-limit", 0.3,
			`Define the sync frequency upper limit`)

		publishStatusAddress = flags.String("publish-status-address", "",
			`Customized address to set as the load-balancer status of Ingress objects this controller satisfies.
Requires the update-status parameter.`)

		dynamicConfigurationEnabled = flags.Bool("enable-dynamic-configuration", true,
			`Dynamically refresh backends on topology changes instead of reloading NGINX.
Feature backed by OpenResty Lua libraries.`)

		httpPort      = flags.Int("http-port", 80, `Port to use for servicing HTTP traffic.`)
		httpsPort     = flags.Int("https-port", 443, `Port to use for servicing HTTPS traffic.`)
		statusPort    = flags.Int("status-port", 18080, `Port to use for exposing NGINX status pages.`)
		sslProxyPort  = flags.Int("ssl-passthrough-proxy-port", 442, `Port to use internally for SSL Passthrough.`)
		defServerPort = flags.Int("default-server-port", 8181, `Port to use for exposing the default server (catch-all).`)
		healthzPort   = flags.Int("healthz-port", 10254, "Port to use for the healthz endpoint.")
	)

	flag.Set("logtostderr", "true")

	flags.AddGoFlagSet(flag.CommandLine)
	flags.Parse(os.Args)

	// Workaround for this issue:
	// https://github.com/kubernetes/kubernetes/issues/17162
	flag.CommandLine.Parse([]string{})

	pflag.VisitAll(func(flag *pflag.Flag) {
		glog.V(2).Infof("FLAG: --%s=%q", flag.Name, flag.Value)
	})

	if *showVersion {
		return true, nil, nil
	}

	if *defaultSvc == "" {
		return false, nil, fmt.Errorf("Please specify --default-backend-service")
	}

	if *ingressClass != "" {
		glog.Infof("Watching for Ingress class: %s", *ingressClass)

		if *ingressClass != class.DefaultClass {
			glog.Warningf("Only Ingresses with class %q will be processed by this Ingress controller", *ingressClass)
		}

		class.IngressClass = *ingressClass
	}

	parser.AnnotationsPrefix = *annotationsPrefix

	// check port collisions
	if !ing_net.IsPortAvailable(*httpPort) {
		return false, nil, fmt.Errorf("Port %v is already in use. Please check the flag --http-port", *httpPort)
	}

	if !ing_net.IsPortAvailable(*httpsPort) {
		return false, nil, fmt.Errorf("Port %v is already in use. Please check the flag --https-port", *httpsPort)
	}

	if !ing_net.IsPortAvailable(*statusPort) {
		return false, nil, fmt.Errorf("Port %v is already in use. Please check the flag --status-port", *statusPort)
	}

	if !ing_net.IsPortAvailable(*defServerPort) {
		return false, nil, fmt.Errorf("Port %v is already in use. Please check the flag --default-server-port", *defServerPort)
	}

	if *enableSSLPassthrough && !ing_net.IsPortAvailable(*sslProxyPort) {
		return false, nil, fmt.Errorf("Port %v is already in use. Please check the flag --ssl-passtrough-proxy-port", *sslProxyPort)
	}

	if !*enableSSLChainCompletion {
		glog.Warningf("SSL certificate chain completion is disabled (--enable-ssl-chain-completion=false)")
	}

	// LuaJIT is not available on arch s390x and ppc64le
	disableLua := false
	if runtime.GOARCH == "s390x" || runtime.GOARCH == "ppc64le" {
		disableLua = true
		if *dynamicConfigurationEnabled {
			*dynamicConfigurationEnabled = false
			glog.Warningf("LuaJIT is not available on s390x and ppc64le architectures: disabling dynamic configuration feature.")
		}
	}

	config := &controller.Configuration{
		APIServerHost:               *apiserverHost,
		KubeConfigFile:              *kubeConfigFile,
		UpdateStatus:                *updateStatus,
		ElectionID:                  *electionID,
		EnableProfiling:             *profiling,
		EnableSSLPassthrough:        *enableSSLPassthrough,
		EnableSSLChainCompletion:    *enableSSLChainCompletion,
		ResyncPeriod:                *resyncPeriod,
		DefaultService:              *defaultSvc,
		Namespace:                   *watchNamespace,
		ConfigMapName:               *configMap,
		TCPConfigMapName:            *tcpConfigMapName,
		UDPConfigMapName:            *udpConfigMapName,
		DefaultSSLCertificate:       *defSSLCertificate,
		DefaultHealthzURL:           *defHealthzURL,
		PublishService:              *publishSvc,
		PublishStatusAddress:        *publishStatusAddress,
		ForceNamespaceIsolation:     *forceIsolation,
		UpdateStatusOnShutdown:      *updateStatusOnShutdown,
		SortBackends:                *sortBackends,
		UseNodeInternalIP:           *useNodeInternalIP,
		SyncRateLimit:               *syncRateLimit,
		DynamicConfigurationEnabled: *dynamicConfigurationEnabled,
		DisableLua:                  disableLua,
		ListenPorts: &ngx_config.ListenPorts{
			Default:  *defServerPort,
			Health:   *healthzPort,
			HTTP:     *httpPort,
			HTTPS:    *httpsPort,
			SSLProxy: *sslProxyPort,
			Status:   *statusPort,
		},
	}

	return false, config, nil
}
<commit_msg>Fixed typo in flags.go<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package main

import (
	"flag"
	"fmt"
	"os"
	"runtime"

	"github.com/golang/glog"
	"github.com/spf13/pflag"

	apiv1 "k8s.io/api/core/v1"

	"k8s.io/ingress-nginx/internal/ingress/annotations/class"
	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
	"k8s.io/ingress-nginx/internal/ingress/controller"
	ngx_config "k8s.io/ingress-nginx/internal/ingress/controller/config"
	ing_net "k8s.io/ingress-nginx/internal/net"
)

func parseFlags() (bool, *controller.Configuration, error) {
	var (
		flags = pflag.NewFlagSet("", pflag.ExitOnError)

		apiserverHost = flags.String("apiserver-host", "",
			`Address of the Kubernetes API server.
Takes the form "protocol://address:port". If not specified, it is assumed the
program runs inside a Kubernetes cluster and local discovery is attempted.`)

		kubeConfigFile = flags.String("kubeconfig", "",
			`Path to a kubeconfig file containing authorization and API server information.`)

		defaultSvc = flags.String("default-backend-service", "",
			`Service used to serve HTTP requests not matching any known server name (catch-all).
Takes the form "namespace/name". The controller configures NGINX to forward
requests to the first port of this Service.`)

		ingressClass = flags.String("ingress-class", "",
			`Name of the ingress class this controller satisfies.
The class of an Ingress object is set using the annotation "kubernetes.io/ingress.class".
All ingress classes are satisfied if this parameter is left empty.`)

		configMap = flags.String("configmap", "",
			`Name of the ConfigMap containing custom global configurations for the controller.`)

		publishSvc = flags.String("publish-service", "",
			`Service fronting the Ingress controller.
Takes the form "namespace/name". When used together with update-status, the
controller mirrors the address of this service's endpoints to the load-balancer
status of all Ingress objects it satisfies.`)

		tcpConfigMapName = flags.String("tcp-services-configmap", "",
			`Name of the ConfigMap containing the definition of the TCP services to expose.
The key in the map indicates the external port to be used. The value is a
reference to a Service in the form "namespace/name:port", where "port" can
either be a port number or name. TCP ports 80 and 443 are reserved by the
controller for servicing HTTP traffic.`)

		udpConfigMapName = flags.String("udp-services-configmap", "",
			`Name of the ConfigMap containing the definition of the UDP services to expose.
The key in the map indicates the external port to be used. The value is a
reference to a Service in the form "namespace/name:port", where "port" can
either be a port name or number.`)

		resyncPeriod = flags.Duration("sync-period", 0,
			`Period at which the controller forces the repopulation of its local object stores. Disabled by default.`)

		watchNamespace = flags.String("watch-namespace", apiv1.NamespaceAll,
			`Namespace the controller watches for updates to Kubernetes objects.
This includes Ingresses, Services and all configuration resources. All
namespaces are watched if this parameter is left empty.`)

		profiling = flags.Bool("profiling", true,
			`Enable profiling via web interface host:port/debug/pprof/`)

		defSSLCertificate = flags.String("default-ssl-certificate", "",
			`Secret containing a SSL certificate to be used by the default HTTPS server (catch-all).
Takes the form "namespace/name".`)

		defHealthzURL = flags.String("health-check-path", "/healthz",
			`URL path of the health check endpoint.
Configured inside the NGINX status server. All requests received on the port
defined by the healthz-port parameter are forwarded internally to this path.`)

		updateStatus = flags.Bool("update-status", true,
			`Update the load-balancer status of Ingress objects this controller satisfies.
Requires setting the publish-service parameter to a valid Service reference.`)

		electionID = flags.String("election-id", "ingress-controller-leader",
			`Election id to use for Ingress status updates.`)

		forceIsolation = flags.Bool("force-namespace-isolation", false,
			`Force namespace isolation.
Prevents Ingress objects from referencing Secrets and ConfigMaps located in a
different namespace than their own. May be used together with watch-namespace.`)

		updateStatusOnShutdown = flags.Bool("update-status-on-shutdown", true,
			`Update the load-balancer status of Ingress objects when the controller shuts down.
Requires the update-status parameter.`)

		sortBackends = flags.Bool("sort-backends", false,
			`Sort servers inside NGINX upstreams.`)

		useNodeInternalIP = flags.Bool("report-node-internal-ip-address", false,
			`Set the load-balancer status of Ingress objects to internal Node addresses instead of external.
Requires the update-status parameter.`)

		showVersion = flags.Bool("version", false,
			`Show release information about the NGINX Ingress controller and exit.`)

		enableSSLPassthrough = flags.Bool("enable-ssl-passthrough", false,
			`Enable SSL Passthrough.`)

		annotationsPrefix = flags.String("annotations-prefix", "nginx.ingress.kubernetes.io",
			`Prefix of the Ingress annotations specific to the NGINX controller.`)

		enableSSLChainCompletion = flags.Bool("enable-ssl-chain-completion", true,
			`Autocomplete SSL certificate chains with missing intermediate CA certificates.
A valid certificate chain is required to enable OCSP stapling. Certificates
uploaded to Kubernetes must have the "Authority Information Access" X.509 v3
extension for this to succeed.`)

		syncRateLimit = flags.Float32("sync-rate-limit", 0.3,
			`Define the sync frequency upper limit`)

		publishStatusAddress = flags.String("publish-status-address", "",
			`Customized address to set as the load-balancer status of Ingress objects this controller satisfies.
Requires the update-status parameter.`)

		dynamicConfigurationEnabled = flags.Bool("enable-dynamic-configuration", true,
			`Dynamically refresh backends on topology changes instead of reloading NGINX.
Feature backed by OpenResty Lua libraries.`)

		httpPort      = flags.Int("http-port", 80, `Port to use for servicing HTTP traffic.`)
		httpsPort     = flags.Int("https-port", 443, `Port to use for servicing HTTPS traffic.`)
		statusPort    = flags.Int("status-port", 18080, `Port to use for exposing NGINX status pages.`)
		sslProxyPort  = flags.Int("ssl-passthrough-proxy-port", 442, `Port to use internally for SSL Passthrough.`)
		defServerPort = flags.Int("default-server-port", 8181, `Port to use for exposing the default server (catch-all).`)
		healthzPort   = flags.Int("healthz-port", 10254, "Port to use for the healthz endpoint.")
	)

	flag.Set("logtostderr", "true")

	flags.AddGoFlagSet(flag.CommandLine)
	flags.Parse(os.Args)

	// Workaround for this issue:
	// https://github.com/kubernetes/kubernetes/issues/17162
	flag.CommandLine.Parse([]string{})

	pflag.VisitAll(func(flag *pflag.Flag) {
		glog.V(2).Infof("FLAG: --%s=%q", flag.Name, flag.Value)
	})

	if *showVersion {
		return true, nil, nil
	}

	if *defaultSvc == "" {
		return false, nil, fmt.Errorf("Please specify --default-backend-service")
	}

	if *ingressClass != "" {
		glog.Infof("Watching for Ingress class: %s", *ingressClass)

		if *ingressClass != class.DefaultClass {
			glog.Warningf("Only Ingresses with class %q will be processed by this Ingress controller", *ingressClass)
		}

		class.IngressClass = *ingressClass
	}

	parser.AnnotationsPrefix = *annotationsPrefix

	// check port collisions
	if !ing_net.IsPortAvailable(*httpPort) {
		return false, nil, fmt.Errorf("Port %v is already in use. Please check the flag --http-port", *httpPort)
	}

	if !ing_net.IsPortAvailable(*httpsPort) {
		return false, nil, fmt.Errorf("Port %v is already in use. Please check the flag --https-port", *httpsPort)
	}

	if !ing_net.IsPortAvailable(*statusPort) {
		return false, nil, fmt.Errorf("Port %v is already in use. Please check the flag --status-port", *statusPort)
	}

	if !ing_net.IsPortAvailable(*defServerPort) {
		return false, nil, fmt.Errorf("Port %v is already in use. Please check the flag --default-server-port", *defServerPort)
	}

	if *enableSSLPassthrough && !ing_net.IsPortAvailable(*sslProxyPort) {
		return false, nil, fmt.Errorf("Port %v is already in use. Please check the flag --ssl-passthrough-proxy-port", *sslProxyPort)
	}

	if !*enableSSLChainCompletion {
		glog.Warningf("SSL certificate chain completion is disabled (--enable-ssl-chain-completion=false)")
	}

	// LuaJIT is not available on arch s390x and ppc64le
	disableLua := false
	if runtime.GOARCH == "s390x" || runtime.GOARCH == "ppc64le" {
		disableLua = true
		if *dynamicConfigurationEnabled {
			*dynamicConfigurationEnabled = false
			glog.Warningf("LuaJIT is not available on s390x and ppc64le architectures: disabling dynamic configuration feature.")
		}
	}

	config := &controller.Configuration{
		APIServerHost:               *apiserverHost,
		KubeConfigFile:              *kubeConfigFile,
		UpdateStatus:                *updateStatus,
		ElectionID:                  *electionID,
		EnableProfiling:             *profiling,
		EnableSSLPassthrough:        *enableSSLPassthrough,
		EnableSSLChainCompletion:    *enableSSLChainCompletion,
		ResyncPeriod:                *resyncPeriod,
		DefaultService:              *defaultSvc,
		Namespace:                   *watchNamespace,
		ConfigMapName:               *configMap,
		TCPConfigMapName:            *tcpConfigMapName,
		UDPConfigMapName:            *udpConfigMapName,
		DefaultSSLCertificate:       *defSSLCertificate,
		DefaultHealthzURL:           *defHealthzURL,
		PublishService:              *publishSvc,
		PublishStatusAddress:        *publishStatusAddress,
		ForceNamespaceIsolation:     *forceIsolation,
		UpdateStatusOnShutdown:      *updateStatusOnShutdown,
		SortBackends:                *sortBackends,
		UseNodeInternalIP:           *useNodeInternalIP,
		SyncRateLimit:               *syncRateLimit,
		DynamicConfigurationEnabled: *dynamicConfigurationEnabled,
		DisableLua:                  disableLua,
		ListenPorts: &ngx_config.ListenPorts{
			Default:  *defServerPort,
			Health:   *healthzPort,
			HTTP:     *httpPort,
			HTTPS:    *httpsPort,
			SSLProxy: *sslProxyPort,
			Status:   *statusPort,
		},
	}

	return false, config, nil
}
<|endoftext|>


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

/*
Present displays slide presentations and articles. It runs a web server that
presents slide and article files from the current directory.

It may be run as a stand-alone command or an App Engine app.
Instructions for deployment to App Engine are in the README of the
code.google.com/p/go.tools repository.

Usage of present:
  -base="": base path for slide template and static resources
  -http="127.0.0.1:3999": host:port to listen on

Input files are named foo.extension, where "extension" defines the format of
the generated output. The supported formats are:
	.slide        // HTML5 slide presentation
	.article      // article format, such as a blog post

The present file format is documented by the present package:
http://godoc.org/code.google.com/p/go.tools/present
*/
package main
<commit_msg>go.tools/cmd/present: update doc<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Present displays slide presentations and articles. It runs a web server that
presents slide and article files from the current directory.

It may be run as a stand-alone command or an App Engine app.
Instructions for deployment to App Engine are in the README of the
code.google.com/p/go.tools repository.

Usage of present:
  -base="": base path for slide template and static resources
  -http="127.0.0.1:3999": HTTP service address (e.g., '127.0.0.1:3999')
  -nacl=false: use Native Client environment playground (prevents non-Go code execution)
  -orighost="": host component of web origin URL (e.g., 'localhost')
  -play=true: enable playground (permit execution of arbitrary user code)

The setup of the Go version of NaCl is documented at:
https://code.google.com/p/go-wiki/wiki/NativeClient

Input files are named foo.extension, where "extension" defines the format of
the generated output. The supported formats are:
	.slide        // HTML5 slide presentation
	.article      // article format, such as a blog post

The present file format is documented by the present package:
http://godoc.org/code.google.com/p/go.tools/present
*/
package main
<|endoftext|>


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

// resgen is a small CLI tool that automatically generates Resource from an API.
package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"go/format"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"text/template"

	gojson "github.com/ChimeraCoder/gojson"

	"e-xpert_solutions/f5-rest-client/f5"
)

var tmpl = `// Copyright e-Xpert Solutions SA. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package {{ .Pkg }}

import "e-xpert_solutions/f5-rest-client/f5"

type {{ .Name }}ConfigList struct {
	Items []{{ .Name }}Config ` + "`json:\"items\"`" + `
	Kind string ` + "`json:\"kind\"`" + `
	SelfLink string ` + "`json:\"selflink\"`" + `
}

type {{ .Name }}Config struct {
	{{ .ItemDef }}
}

const {{ .Name }}Endpoint = "{{ .Endpoint }}"

type {{ .Name }}Resource struct {
	c f5.Client
}

func (r *{{ .Name }}Resource) ListAll() (*{{ .Name }}Config, error) {
	var list {{ .Name }}ConfigList
	if err := r.c.ReadQuery(BasePath+{{ .Name }}Endpoint, &list); err != nil {
		return nil, err
	}
	return &list, nil
}

func (r *{{ .Name }}Resource) Get(id string) (*{{ .Name }}Config, error) {
	var item {{ .Name }}Config
	if err := r.c.ReadQuery(BasePath+{{ .Name }}Endpoint, &item); err != nil {
		return nil, err
	}
	return &item, nil
}

func (r *{{ .Name }}Resource) Create(item {{ .Name }}Config) error {
	if err := r.c.ModQuery("POST", BasePath + {{ .Name }}Endpoint, item); err != nil {
		return err
	}
	return nil
}

func (r *{{ .Name }}Resource) Edit(id string, item {{ .Name }}Config) error {
	if err := r.c.ModQuery("PUT", BasePath + {{ .Name }}Endpoint + "/" + id, item); err != nil {
		return err
	}
	return nil
}

func (r *{{ .Name }}Resource) Delete(id string) error {
	if err := r.c.ModQuery("DELETE", BasePath + {{ .Name }}Endpoint + "/"+id, nil); err != nil {
		return err
	}
	return nil
}
`

var t = template.Must(template.New("resource").Parse(tmpl))

type templateData struct {
	Name     string
	ItemDef  string
	Pkg      string
	Endpoint string
}

func renderTemplate(outputDir string, data templateData) error {
	path := filepath.Join(outputDir, strings.ToLower(data.Name)+".go")
	if _, err := os.Stat(path); err == nil {
		return errors.New(path + " already exists")
	}
	f, err := os.Create(path)
	if err != nil {
		return fmt.Errorf("failed to create output file '%s' for %s resource: %v", path, data.Name, err)
	}
	defer f.Close()
	var buf bytes.Buffer
	if err := t.Execute(&buf, data); err != nil {
		return fmt.Errorf("failed to render template for %s resource: %v", data.Name, err)
	}
	bs, err := format.Source(buf.Bytes())
	if err != nil {
		return fmt.Errorf("failed to format generated file: %v", err)
	}
	if _, err := f.Write(bs); err != nil {
		return fmt.Errorf("failed to write generated file: %v", err)
	}
	return nil
}

var re = regexp.MustCompile("Items \\[\\]struct \\{(.*)\\} `json:\"items\"`")

func findItemDef(s string) string {
	matches := re.FindAllStringSubmatch(strings.Replace(s, "\n", "<°BREAK°>", -1), -1)
	return strings.Replace(matches[0][1], "<°BREAK°>", "\n", -1)
}

type config struct {
	BaseURL  string `json:"base_url"`
	User     string `json:"username"`
	Password string `json:"password"`
	API      map[string]struct {
		RESTPath string `json:"rest_path"`
		Endpoint string `json:"endpoint"`
	} `json:"api"`
}

func parseConfig(path string) (*config, error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, fmt.Errorf("failed to open config file: %v", err)
	}
	defer f.Close()
	var cfg config
	dec := json.NewDecoder(f)
	if err := dec.Decode(&cfg); err != nil {
		return nil, fmt.Errorf("failed to parse config file: %v", err)
	}
	return &cfg, nil
}

var (
	cfgPath   = flag.String("c", "resgen.conf", "configuration file path")
	outputDir = flag.String("o", ".", "output directory")
	pkgName   = flag.String("p", "foo", "package name")
)

func main() {
	flag.Parse()

	if info, err := os.Stat(*outputDir); err != nil {
		log.Fatal(err)
	} else if !info.IsDir() {
		log.Fatalf("'%s' is not a directory", *outputDir)
	}

	cfg, err := parseConfig(*cfgPath)
	if err != nil {
		log.Fatal(err)
	}

	f5Client, err := f5.NewBasicClient(cfg.BaseURL, cfg.User, cfg.Password)
	if err != nil {
		log.Fatal(err)
	}
	f5Client.DisableCertCheck()

	for name, settings := range cfg.API {
		req, err := f5Client.MakeRequest("GET", settings.RESTPath, nil)
		if err != nil {
			log.Print("failed to create http request", settings.RESTPath, ": ", err)
			continue
		}
		resp, err := f5Client.Do(req)
		if err != nil {
			log.Print("failed to query ", settings.RESTPath, ": ", err)
			continue
		}
		defer resp.Body.Close()
		listDef, err := gojson.Generate(resp.Body, name, *pkgName)
		if err != nil {
			log.Print("failed to generate structure for ", settings.RESTPath, ": ", err)
			continue
		}
		data := templateData{
			Name:     name,
			ItemDef:  findItemDef(string(listDef)),
			Pkg:      *pkgName,
			Endpoint: settings.Endpoint,
		}
		if err := renderTemplate(*outputDir, data); err != nil {
			log.Print("failed to render template: ", err)
		}
	}
}
<commit_msg>cmd/resgen: fix type inssue in generated methods<commit_after>// Copyright 2014-2016 The project AUTHORS. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// resgen is a small CLI tool that automatically generates Resource from an API.
package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"go/format"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"text/template"

	gojson "github.com/ChimeraCoder/gojson"

	"e-xpert_solutions/f5-rest-client/f5"
)

var tmpl = `// Copyright e-Xpert Solutions SA. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package {{ .Pkg }}

import "e-xpert_solutions/f5-rest-client/f5"

type {{ .Name }}ConfigList struct {
	Items []{{ .Name }}Config ` + "`json:\"items\"`" + `
	Kind string ` + "`json:\"kind\"`" + `
	SelfLink string ` + "`json:\"selflink\"`" + `
}

type {{ .Name }}Config struct {
	{{ .ItemDef }}
}

const {{ .Name }}Endpoint = "{{ .Endpoint }}"

type {{ .Name }}Resource struct {
	c f5.Client
}

func (r *{{ .Name }}Resource) ListAll() (*{{ .Name }}ConfigList, error) {
	var list {{ .Name }}ConfigList
	if err := r.c.ReadQuery(BasePath+{{ .Name }}Endpoint, &list); err != nil {
		return nil, err
	}
	return &list, nil
}

func (r *{{ .Name }}Resource) Get(id string) (*{{ .Name }}Config, error) {
	var item {{ .Name }}Config
	if err := r.c.ReadQuery(BasePath+{{ .Name }}Endpoint, &item); err != nil {
		return nil, err
	}
	return &item, nil
}

func (r *{{ .Name }}Resource) Create(item {{ .Name }}Config) error {
	if err := r.c.ModQuery("POST", BasePath + {{ .Name }}Endpoint, item); err != nil {
		return err
	}
	return nil
}

func (r *{{ .Name }}Resource) Edit(id string, item {{ .Name }}Config) error {
	if err := r.c.ModQuery("PUT", BasePath + {{ .Name }}Endpoint + "/" + id, item); err != nil {
		return err
	}
	return nil
}

func (r *{{ .Name }}Resource) Delete(id string) error {
	if err := r.c.ModQuery("DELETE", BasePath + {{ .Name }}Endpoint + "/"+id, nil); err != nil {
		return err
	}
	return nil
}
`

var t = template.Must(template.New("resource").Parse(tmpl))

type templateData struct {
	Name     string
	ItemDef  string
	Pkg      string
	Endpoint string
}

func renderTemplate(outputDir string, data templateData) error {
	path := filepath.Join(outputDir, strings.ToLower(data.Name)+".go")
	if _, err := os.Stat(path); err == nil {
		return errors.New(path + " already exists")
	}
	f, err := os.Create(path)
	if err != nil {
		return fmt.Errorf("failed to create output file '%s' for %s resource: %v", path, data.Name, err)
	}
	defer f.Close()
	var buf bytes.Buffer
	if err := t.Execute(&buf, data); err != nil {
		return fmt.Errorf("failed to render template for %s resource: %v", data.Name, err)
	}
	bs, err := format.Source(buf.Bytes())
	if err != nil {
		return fmt.Errorf("failed to format generated file: %v", err)
	}
	if _, err := f.Write(bs); err != nil {
		return fmt.Errorf("failed to write generated file: %v", err)
	}
	return nil
}

var re = regexp.MustCompile("Items \\[\\]struct \\{(.*)\\} `json:\"items\"`")

func findItemDef(s string) string {
	log.Print("s = ", s)
	matches := re.FindAllStringSubmatch(strings.Replace(s, "\n", "<°BREAK°>", -1), -1)
	if len(matches) > 0 && len(matches[0]) > 1 {
		return strings.Replace(matches[0][1], "<°BREAK°>", "\n", -1)
	}
	return ""
}

type config struct {
	BaseURL  string `json:"base_url"`
	User     string `json:"username"`
	Password string `json:"password"`
	API      map[string]struct {
		RESTPath string `json:"rest_path"`
		Endpoint string `json:"endpoint"`
	} `json:"api"`
}

func parseConfig(path string) (*config, error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, fmt.Errorf("failed to open config file: %v", err)
	}
	defer f.Close()
	var cfg config
	dec := json.NewDecoder(f)
	if err := dec.Decode(&cfg); err != nil {
		return nil, fmt.Errorf("failed to parse config file: %v", err)
	}
	return &cfg, nil
}

var (
	cfgPath   = flag.String("c", "resgen.conf", "configuration file path")
	outputDir = flag.String("o", ".", "output directory")
	pkgName   = flag.String("p", "foo", "package name")
)

func main() {
	flag.Parse()

	if info, err := os.Stat(*outputDir); err != nil {
		log.Fatal(err)
	} else if !info.IsDir() {
		log.Fatalf("'%s' is not a directory", *outputDir)
	}

	cfg, err := parseConfig(*cfgPath)
	if err != nil {
		log.Fatal(err)
	}

	f5Client, err := f5.NewBasicClient(cfg.BaseURL, cfg.User, cfg.Password)
	if err != nil {
		log.Fatal(err)
	}
	f5Client.DisableCertCheck()

	for name, settings := range cfg.API {
		req, err := f5Client.MakeRequest("GET", settings.RESTPath, nil)
		if err != nil {
			log.Print("failed to create http request", settings.RESTPath, ": ", err)
			continue
		}
		resp, err := f5Client.Do(req)
		if err != nil {
			log.Print("failed to query ", settings.RESTPath, ": ", err)
			continue
		}
		defer resp.Body.Close()
		listDef, err := gojson.Generate(resp.Body, name, *pkgName)
		if err != nil {
			log.Print("failed to generate structure for ", settings.RESTPath, ": ", err)
			continue
		}
		data := templateData{
			Name:     name,
			ItemDef:  findItemDef(string(listDef)),
			Pkg:      *pkgName,
			Endpoint: settings.Endpoint,
		}
		if err := renderTemplate(*outputDir, data); err != nil {
			log.Print("failed to render template: ", err)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	"github.com/go-kit/kit/log"

	"github.com/moov-io/ach/server"
)

/**
CreateFile
curl -d '{"id":"08B751B2","immediateDestination":"9876543210", "immediateDestinationName":"Federal Reserve Bank", "immediateOrigin":"1234567890","immediateOriginName":"My Bank Name"}' -H "Content-Type: application/json" -X POST http://localhost:8080/files/

GetFile
curl -H "Content-Type: application/json" -X GET http://localhost:8080/files/1234

GetFiles
curl -H "Content-Type: application/json" -X GET http://localhost:8080/files/

DeleteFile
curl -H "Content-Type: application/json" -X DELETE http://localhost:8080/files/1234

CreateBatch
curl -d '{"id":"54321","serviceClassCode":220,"standardEntryClassCode":"WEB","companyName":"Your Company inc","companyIdentification":"121042882","companyEntryDescription":"Online Order","ODFIIdentification":"12104288"}' -H "Content-Type: application/json" -X POST http://localhost:8080/files/08B751B2/batches/

GetBatch
curl -H "Content-Type: application/json" -X GET http://localhost:8080/files/08B751B2/batches/54321

GetBatches
curl -H "Content-Type: application/json" -X GET http://localhost:8080/files/08B751B2/batches/

DeleteBatch
curl -H "Content-Type: application/json" -X DELETE http://localhost:8080/files/08B751B2/batches/54321
**/

var (
	httpAddr = flag.String("http.addr", ":8080", "HTTP listen address")
	logger log.Logger

	svc server.Service
	handler http.Handler
)

func main() {
	flag.Parse()

	// Setup logging, default to stdout
	logger = log.NewLogfmtLogger(os.Stderr)
	logger = log.With(logger, "ts", log.DefaultTimestampUTC)
	logger = log.With(logger, "caller", log.DefaultCaller)

	// Setup underlying ach service
	svc = server.NewService(server.NewRepositoryInMemory())
	svc = server.LoggingMiddleware(logger)(svc)

	// Create HTTP server
	handler = server.MakeHTTPHandler(svc, log.With(logger, "component", "HTTP"))

	// Listen for application termination.
	errs := make(chan error)
	go func() {
		c := make(chan os.Signal)
		signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
		errs <- fmt.Errorf("%s", <-c)
	}()

	go func() {
		logger.Log("transport", "HTTP", "addr", *httpAddr)
		errs <- http.ListenAndServe(*httpAddr, handler)
	}()

	logger.Log("exit", <-errs)
}
<commit_msg>go fmt<commit_after>package main

import (
	"flag"
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	"github.com/go-kit/kit/log"

	"github.com/moov-io/ach/server"
)

/**
CreateFile
curl -d '{"id":"08B751B2","immediateDestination":"9876543210", "immediateDestinationName":"Federal Reserve Bank", "immediateOrigin":"1234567890","immediateOriginName":"My Bank Name"}' -H "Content-Type: application/json" -X POST http://localhost:8080/files/

GetFile
curl -H "Content-Type: application/json" -X GET http://localhost:8080/files/1234

GetFiles
curl -H "Content-Type: application/json" -X GET http://localhost:8080/files/

DeleteFile
curl -H "Content-Type: application/json" -X DELETE http://localhost:8080/files/1234

CreateBatch
curl -d '{"id":"54321","serviceClassCode":220,"standardEntryClassCode":"WEB","companyName":"Your Company inc","companyIdentification":"121042882","companyEntryDescription":"Online Order","ODFIIdentification":"12104288"}' -H "Content-Type: application/json" -X POST http://localhost:8080/files/08B751B2/batches/

GetBatch
curl -H "Content-Type: application/json" -X GET http://localhost:8080/files/08B751B2/batches/54321

GetBatches
curl -H "Content-Type: application/json" -X GET http://localhost:8080/files/08B751B2/batches/

DeleteBatch
curl -H "Content-Type: application/json" -X DELETE http://localhost:8080/files/08B751B2/batches/54321
**/

var (
	httpAddr = flag.String("http.addr", ":8080", "HTTP listen address")
	logger   log.Logger

	svc     server.Service
	handler http.Handler
)

func main() {
	flag.Parse()

	// Setup logging, default to stdout
	logger = log.NewLogfmtLogger(os.Stderr)
	logger = log.With(logger, "ts", log.DefaultTimestampUTC)
	logger = log.With(logger, "caller", log.DefaultCaller)

	// Setup underlying ach service
	svc = server.NewService(server.NewRepositoryInMemory())
	svc = server.LoggingMiddleware(logger)(svc)

	// Create HTTP server
	handler = server.MakeHTTPHandler(svc, log.With(logger, "component", "HTTP"))

	// Listen for application termination.
	errs := make(chan error)
	go func() {
		c := make(chan os.Signal)
		signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
		errs <- fmt.Errorf("%s", <-c)
	}()

	go func() {
		logger.Log("transport", "HTTP", "addr", *httpAddr)
		errs <- http.ListenAndServe(*httpAddr, handler)
	}()

	logger.Log("exit", <-errs)
}
<|endoftext|>


<commit_before>// Copyright 2015, David Howden
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
tchaik creates a webserver which serves the web UI.

It is assumed that tchaik is run relatively local to the user (i.e. serving pages to the local machine, or a local
network).

All configuration is done through command line parameters.

A common use case is to begin by use using an existing iTunes Library file:

  tchaik -itlXML /path/to/iTunesMusicLibrary.xml

*/
package main

import (
	"crypto/tls"
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/tchaik/tchaik/index"
	"github.com/tchaik/tchaik/index/attr"
	"github.com/tchaik/tchaik/index/history"
	"github.com/tchaik/tchaik/index/itl"
	"github.com/tchaik/tchaik/index/walk"
	"github.com/tchaik/tchaik/store"
	"github.com/tchaik/tchaik/store/cmdflag"
)

var debug bool
var itlXML, tchLib, walkPath string

var playHistoryPath string

var listenAddr string
var staticDir string
var certFile, keyFile string

var authUser, authPassword string

var traceListenAddr string

func init() {
	flag.BoolVar(&debug, "debug", false, "print debugging information")

	flag.StringVar(&listenAddr, "listen", "localhost:8080", "bind address to http listen")
	flag.StringVar(&certFile, "tls-cert", "", "path to a certificate file, must also specify -tls-key")
	flag.StringVar(&keyFile, "tls-key", "", "path to a certificate key file, must also specify -tls-cert")

	flag.StringVar(&itlXML, "itlXML", "", "path to iTunes Library XML file")
	flag.StringVar(&tchLib, "lib", "", "path to Tchaik library file")
	flag.StringVar(&walkPath, "path", "", "path to directory containing music files (to build index from)")

	flag.StringVar(&playHistoryPath, "play-history", "history.json", "path to play history file")

	flag.StringVar(&staticDir, "static-dir", "ui/static", "Path to the static asset directory")

	flag.StringVar(&authUser, "auth-user", "", "username to use for HTTP authentication (set to enable)")
	flag.StringVar(&authPassword, "auth-password", "", "password to use for HTTP authentication")

	flag.StringVar(&traceListenAddr, "trace-listen", "", "bind address for trace HTTP server")
}

func readLibrary() (index.Library, error) {
	var count int
	check := func(x string) {
		if x != "" {
			count++
		}
	}
	check(itlXML)
	check(tchLib)
	check(walkPath)

	switch {
	case count == 0:
		return nil, fmt.Errorf("must specify one library file or a path to build one from (-itlXML, -lib or -path)")
	case count > 1:
		return nil, fmt.Errorf("must only specify one library file or a path to build one from (-itlXML, -lib or -path)")
	}

	var lib index.Library
	switch {
	case tchLib != "":
		f, err := os.Open(tchLib)
		if err != nil {
			return nil, fmt.Errorf("could not open Tchaik library file: %v", err)
		}
		defer f.Close()

		fmt.Printf("Parsing %v...", tchLib)
		lib, err = index.ReadFrom(f)
		if err != nil {
			return nil, fmt.Errorf("error parsing Tchaik library file: %v\n", err)
		}
		fmt.Println("done.")
		return lib, nil

	case itlXML != "":
		f, err := os.Open(itlXML)
		if err != nil {
			return nil, fmt.Errorf("could open iTunes library file: %v", err)
		}
		defer f.Close()

		lib, err = itl.ReadFrom(f)
		if err != nil {
			return nil, fmt.Errorf("error parsing iTunes library file: %v", err)
		}

	case walkPath != "":
		fmt.Printf("Walking %v...\n", walkPath)
		lib = walk.NewLibrary(walkPath)
		fmt.Println("Finished walking.")
	}

	fmt.Printf("Building Tchaik Library...")
	lib = index.Convert(lib, "ID")
	fmt.Println("done.")
	return lib, nil
}

func buildRootCollection(l index.Library) index.Collection {
	root := index.Collect(l, index.By(attr.String("Album")))
	index.SortKeysByGroupName(root)
	return root
}

func buildSearchIndex(c index.Collection) index.Searcher {
	wi := index.BuildWordIndex(c, []string{"Composer", "Artist", "Album", "Name"})
	return index.FlatSearcher{
		Searcher: index.WordsIntersectSearcher(index.BuildPrefixExpandSearcher(wi, wi, 10)),
	}
}

func main() {
	flag.Parse()
	l, err := readLibrary()
	if err != nil {
		fmt.Printf("error: %v\n", err)
		os.Exit(1)
	}

	fmt.Printf("Building root collection...")
	root := buildRootCollection(l)
	fmt.Println("done.")

	fmt.Printf("Building artists filter...")
	artists := index.Filter(root, "Artist")
	fmt.Println("done.")

	fmt.Printf("Building recent index...")
	recent := index.Recent(root, 150)
	fmt.Println("done.")

	fmt.Printf("Building search index...")
	searcher := buildSearchIndex(root)
	fmt.Println("done.")

	fmt.Printf("Loading play history...")
	hs, err := history.NewStore(playHistoryPath)
	if err != nil {
		fmt.Printf("\nerror loading play history: %v", err)
		os.Exit(1)
	}
	fmt.Println("done.")

	mediaFileSystem, artworkFileSystem, err := cmdflag.Stores()
	if err != nil {
		fmt.Println("error setting up stores:", err)
		os.Exit(1)
	}

	if debug {
		mediaFileSystem = store.LogFileSystem("Media", mediaFileSystem)
		artworkFileSystem = store.LogFileSystem("Artwork", artworkFileSystem)
	}

	if traceListenAddr != "" {
		fmt.Printf("Starting trace server on http://%v\n", traceListenAddr)
		go func() {
			log.Fatal(http.ListenAndServe(traceListenAddr, nil))
		}()
	}

	lib := Library{
		Library: l,
		collections: map[string]index.Collection{
			"Root": root,
		},
		filters: map[string][]index.FilterItem{
			"Artist": artists,
		},
		recent:   recent,
		searcher: searcher,
	}

	h := NewHandler(lib, hs, mediaFileSystem, artworkFileSystem)

	if certFile != "" && keyFile != "" {
		fmt.Printf("Web server is running on https://%v\n", listenAddr)
		fmt.Println("Quit the server with CTRL-C.")

		tlsConfig := &tls.Config{MinVersion: tls.VersionTLS10}
		server := &http.Server{Addr: listenAddr, Handler: h, TLSConfig: tlsConfig}
		log.Fatal(server.ListenAndServeTLS(certFile, keyFile))
	}

	fmt.Printf("Web server is running on http://%v\n", listenAddr)
	fmt.Println("Quit the server with CTRL-C.")

	log.Fatal(http.ListenAndServe(listenAddr, h))
}
<commit_msg>Fix: BuildWordIndex -> BuildCollectionWordIndex.<commit_after>// Copyright 2015, David Howden
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
tchaik creates a webserver which serves the web UI.

It is assumed that tchaik is run relatively local to the user (i.e. serving pages to the local machine, or a local
network).

All configuration is done through command line parameters.

A common use case is to begin by use using an existing iTunes Library file:

  tchaik -itlXML /path/to/iTunesMusicLibrary.xml

*/
package main

import (
	"crypto/tls"
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/tchaik/tchaik/index"
	"github.com/tchaik/tchaik/index/attr"
	"github.com/tchaik/tchaik/index/history"
	"github.com/tchaik/tchaik/index/itl"
	"github.com/tchaik/tchaik/index/walk"
	"github.com/tchaik/tchaik/store"
	"github.com/tchaik/tchaik/store/cmdflag"
)

var debug bool
var itlXML, tchLib, walkPath string

var playHistoryPath string

var listenAddr string
var staticDir string
var certFile, keyFile string

var authUser, authPassword string

var traceListenAddr string

func init() {
	flag.BoolVar(&debug, "debug", false, "print debugging information")

	flag.StringVar(&listenAddr, "listen", "localhost:8080", "bind address to http listen")
	flag.StringVar(&certFile, "tls-cert", "", "path to a certificate file, must also specify -tls-key")
	flag.StringVar(&keyFile, "tls-key", "", "path to a certificate key file, must also specify -tls-cert")

	flag.StringVar(&itlXML, "itlXML", "", "path to iTunes Library XML file")
	flag.StringVar(&tchLib, "lib", "", "path to Tchaik library file")
	flag.StringVar(&walkPath, "path", "", "path to directory containing music files (to build index from)")

	flag.StringVar(&playHistoryPath, "play-history", "history.json", "path to play history file")

	flag.StringVar(&staticDir, "static-dir", "ui/static", "Path to the static asset directory")

	flag.StringVar(&authUser, "auth-user", "", "username to use for HTTP authentication (set to enable)")
	flag.StringVar(&authPassword, "auth-password", "", "password to use for HTTP authentication")

	flag.StringVar(&traceListenAddr, "trace-listen", "", "bind address for trace HTTP server")
}

func readLibrary() (index.Library, error) {
	var count int
	check := func(x string) {
		if x != "" {
			count++
		}
	}
	check(itlXML)
	check(tchLib)
	check(walkPath)

	switch {
	case count == 0:
		return nil, fmt.Errorf("must specify one library file or a path to build one from (-itlXML, -lib or -path)")
	case count > 1:
		return nil, fmt.Errorf("must only specify one library file or a path to build one from (-itlXML, -lib or -path)")
	}

	var lib index.Library
	switch {
	case tchLib != "":
		f, err := os.Open(tchLib)
		if err != nil {
			return nil, fmt.Errorf("could not open Tchaik library file: %v", err)
		}
		defer f.Close()

		fmt.Printf("Parsing %v...", tchLib)
		lib, err = index.ReadFrom(f)
		if err != nil {
			return nil, fmt.Errorf("error parsing Tchaik library file: %v\n", err)
		}
		fmt.Println("done.")
		return lib, nil

	case itlXML != "":
		f, err := os.Open(itlXML)
		if err != nil {
			return nil, fmt.Errorf("could open iTunes library file: %v", err)
		}
		defer f.Close()

		lib, err = itl.ReadFrom(f)
		if err != nil {
			return nil, fmt.Errorf("error parsing iTunes library file: %v", err)
		}

	case walkPath != "":
		fmt.Printf("Walking %v...\n", walkPath)
		lib = walk.NewLibrary(walkPath)
		fmt.Println("Finished walking.")
	}

	fmt.Printf("Building Tchaik Library...")
	lib = index.Convert(lib, "ID")
	fmt.Println("done.")
	return lib, nil
}

func buildRootCollection(l index.Library) index.Collection {
	root := index.Collect(l, index.By(attr.String("Album")))
	index.SortKeysByGroupName(root)
	return root
}

func buildSearchIndex(c index.Collection) index.Searcher {
	wi := index.BuildCollectionWordIndex(c, []string{"Composer", "Artist", "Album", "Name"})
	return index.FlatSearcher{
		Searcher: index.WordsIntersectSearcher(index.BuildPrefixExpandSearcher(wi, wi, 10)),
	}
}

func main() {
	flag.Parse()
	l, err := readLibrary()
	if err != nil {
		fmt.Printf("error: %v\n", err)
		os.Exit(1)
	}

	fmt.Printf("Building root collection...")
	root := buildRootCollection(l)
	fmt.Println("done.")

	fmt.Printf("Building artists filter...")
	artists := index.Filter(root, "Artist")
	fmt.Println("done.")

	fmt.Printf("Building recent index...")
	recent := index.Recent(root, 150)
	fmt.Println("done.")

	fmt.Printf("Building search index...")
	searcher := buildSearchIndex(root)
	fmt.Println("done.")

	fmt.Printf("Loading play history...")
	hs, err := history.NewStore(playHistoryPath)
	if err != nil {
		fmt.Printf("\nerror loading play history: %v", err)
		os.Exit(1)
	}
	fmt.Println("done.")

	mediaFileSystem, artworkFileSystem, err := cmdflag.Stores()
	if err != nil {
		fmt.Println("error setting up stores:", err)
		os.Exit(1)
	}

	if debug {
		mediaFileSystem = store.LogFileSystem("Media", mediaFileSystem)
		artworkFileSystem = store.LogFileSystem("Artwork", artworkFileSystem)
	}

	if traceListenAddr != "" {
		fmt.Printf("Starting trace server on http://%v\n", traceListenAddr)
		go func() {
			log.Fatal(http.ListenAndServe(traceListenAddr, nil))
		}()
	}

	lib := Library{
		Library: l,
		collections: map[string]index.Collection{
			"Root": root,
		},
		filters: map[string][]index.FilterItem{
			"Artist": artists,
		},
		recent:   recent,
		searcher: searcher,
	}

	h := NewHandler(lib, hs, mediaFileSystem, artworkFileSystem)

	if certFile != "" && keyFile != "" {
		fmt.Printf("Web server is running on https://%v\n", listenAddr)
		fmt.Println("Quit the server with CTRL-C.")

		tlsConfig := &tls.Config{MinVersion: tls.VersionTLS10}
		server := &http.Server{Addr: listenAddr, Handler: h, TLSConfig: tlsConfig}
		log.Fatal(server.ListenAndServeTLS(certFile, keyFile))
	}

	fmt.Printf("Web server is running on http://%v\n", listenAddr)
	fmt.Println("Quit the server with CTRL-C.")

	log.Fatal(http.ListenAndServe(listenAddr, h))
}
<|endoftext|>


<commit_before>// throw stores a file in the cloud, encrypted.
package main

import (
	"crypto/sha256"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path"
	"runtime"
	"runtime/pprof"
	"sync"
	"time"

	"github.com/asjoyner/shade"
	"github.com/asjoyner/shade/config"
	"github.com/asjoyner/shade/drive"
	"github.com/golang/glog"
	"github.com/jpillora/backoff"

	_ "github.com/asjoyner/shade/drive/amazon"
	_ "github.com/asjoyner/shade/drive/cache"
	_ "github.com/asjoyner/shade/drive/encrypt"
	_ "github.com/asjoyner/shade/drive/google"
	_ "github.com/asjoyner/shade/drive/local"
	_ "github.com/asjoyner/shade/drive/memory"
	_ "github.com/asjoyner/shade/drive/win"
)

var (
	defaultConfig = path.Join(shade.ConfigDir(), "config.json")
	configPath    = flag.String("config", defaultConfig, "shade config file")
	// numUploaders has diminishing returns after about 3-4, and meaningfully
	// increases memory usage.  Setting it too high will almost certainly cause
	// OOMs when upload files of more than trivial size.
	numUploaders = flag.Int("numUploaders", 3, "The number of goroutines to upload chunks in parallel.")
	maxRetries   = flag.Int("maxRetries", 10, "The number of times to try to write a chunk to persistent storage.")
	// maxChunks serves as a backstop against accidentaly uploading /dev/urandom
	// ad infinitum, and can be set to a lower value to facilitate testing memory
	// usage, etc.  You may find testdata/config.win.json helpful for this.
	maxChunks = flag.Int("maxChunks", 1000000, "The maximum number of chunks to read for a given file.")
)

type chunkToGo struct {
	chunk      shade.Chunk
	chunkbytes []byte
	manifest   *shade.File
}

func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "\nusage: %s [flags] <filename> <destination filename>\n", path.Base(os.Args[0]))
		flag.PrintDefaults()
	}

	flag.Parse()
	if flag.NArg() != 2 {
		flag.Usage()
		os.Exit(2)
	}

	// read in the config
	config, err := config.Read(*configPath)
	if err != nil {
		fmt.Fprintf(os.Stderr, "could not initialize clients: %s\n", err)
		os.Exit(1)
	}

	start := time.Now()

	// initialize client
	client, err := drive.NewClient(config)
	if err != nil {
		log.Fatalf("could not initialize client: %s\n", err)
	}

	// initialize the goroutines to upload chunks
	uploadRequests := make(chan chunkToGo)
	var workers sync.WaitGroup
	workers.Add(*numUploaders)
	for w := 1; w <= *numUploaders; w++ {
		go func(reqs chan chunkToGo) {
			for r := range reqs {
				numRetries := 0
				b := &backoff.Backoff{Factor: 4}
				for {
					numRetries++
					if err := client.PutChunk(r.chunk.Sha256, r.chunkbytes, r.manifest); err != nil {
						if numRetries >= *maxRetries {
							fmt.Fprintf(os.Stderr, "chunk upload failed: %s\n", err)
							os.Exit(1)
						}
						glog.Errorf("chunk write error, will retry: %s", err)
						time.Sleep(b.Duration())
						continue
					}
					b.Reset()
					break
				}
			}
			workers.Done()
			return
		}(uploadRequests)
	}

	filename := flag.Arg(0)

	manifest := shade.NewFile(flag.Arg(1))

	fh, err := os.Open(filename)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err)
		os.Exit(3)
	}

	var rt runtime.MemStats
	for {
		// Initialize chunk, to ensure each chunk uses a unique nonce
		chunk := shade.NewChunk()
		chunk.Index = len(manifest.Chunks)
		// Initialize chunkbytes, so it's safe for concurrent access later
		chunkbytes := make([]byte, manifest.Chunksize)

		// Read a chunk
		numBytes, err := fh.Read(chunkbytes)
		if err == io.EOF {
			break
		} else if err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", err)
			os.Exit(3)
		} else if len(manifest.Chunks) >= *maxChunks {
			glog.Info("Reached the maximum number of chunks in a single file.")
			break
		}
		manifest.Filesize += int64(numBytes)

		// truncate the chunkbytes array on the last read
		if numBytes < manifest.Chunksize {
			chunkbytes = chunkbytes[:numBytes]
			manifest.LastChunksize = numBytes
		}

		a := sha256.Sum256(chunkbytes)
		chunk.Sha256 = a[:]

		manifest.Chunks = append(manifest.Chunks, chunk)

		if glog.V(3) {
			if (len(manifest.Chunks) % 10) == 0 {
				runtime.ReadMemStats(&rt)
				glog.Infof("%d chunks: %0.2f MBytes Heap, %0.2f MBytes Sys\n", len(manifest.Chunks), float64(rt.Alloc)/1024/1024, float64(rt.Sys)/1024/1024)

				if glog.V(9) {
					f, err := os.Create("/tmp/throw.mprof")
					if err != nil {
						log.Fatal(err)
					}
					pprof.WriteHeapProfile(f)
					f.Close()
				}
			}
		}
		// upload the chunk
		uploadRequests <- chunkToGo{chunk, chunkbytes, manifest}
	}
	close(uploadRequests)
	workers.Wait()

	jm, err := json.Marshal(manifest)
	if err != nil {
		fmt.Fprintf(os.Stderr, "could not marshal file manifest: %s\n", err)
		os.Exit(1)
	}
	// upload the manifest
	a := sha256.Sum256(jm)
	if err := client.PutFile(a[:], jm); err != nil {
		fmt.Fprintf(os.Stderr, "manifest upload failed: %s\n", err)
		os.Exit(1)
	}

	elapsed := time.Since(start)
	size := manifest.Filesize / 1024 / 1024
	MBps := float64(size) / float64(elapsed.Nanoseconds()) / 1000000
	fmt.Printf("Uploaded %d MB in %s at %0.2f MB/s.\n", size, elapsed, MBps)
}
<commit_msg>Correct the division calculating upload speed<commit_after>// throw stores a file in the cloud, encrypted.
package main

import (
	"crypto/sha256"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path"
	"runtime"
	"runtime/pprof"
	"sync"
	"time"

	"github.com/asjoyner/shade"
	"github.com/asjoyner/shade/config"
	"github.com/asjoyner/shade/drive"
	"github.com/golang/glog"
	"github.com/jpillora/backoff"

	_ "github.com/asjoyner/shade/drive/amazon"
	_ "github.com/asjoyner/shade/drive/cache"
	_ "github.com/asjoyner/shade/drive/encrypt"
	_ "github.com/asjoyner/shade/drive/google"
	_ "github.com/asjoyner/shade/drive/local"
	_ "github.com/asjoyner/shade/drive/memory"
	_ "github.com/asjoyner/shade/drive/win"
)

var (
	defaultConfig = path.Join(shade.ConfigDir(), "config.json")
	configPath    = flag.String("config", defaultConfig, "shade config file")
	// numUploaders has diminishing returns after about 3-4, and meaningfully
	// increases memory usage.  Setting it too high will almost certainly cause
	// OOMs when upload files of more than trivial size.
	numUploaders = flag.Int("numUploaders", 3, "The number of goroutines to upload chunks in parallel.")
	maxRetries   = flag.Int("maxRetries", 10, "The number of times to try to write a chunk to persistent storage.")
	// maxChunks serves as a backstop against accidentaly uploading /dev/urandom
	// ad infinitum, and can be set to a lower value to facilitate testing memory
	// usage, etc.  You may find testdata/config.win.json helpful for this.
	maxChunks = flag.Int("maxChunks", 1000000, "The maximum number of chunks to read for a given file.")
)

type chunkToGo struct {
	chunk      shade.Chunk
	chunkbytes []byte
	manifest   *shade.File
}

func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "\nusage: %s [flags] <filename> <destination filename>\n", path.Base(os.Args[0]))
		flag.PrintDefaults()
	}

	flag.Parse()
	if flag.NArg() != 2 {
		flag.Usage()
		os.Exit(2)
	}

	// read in the config
	config, err := config.Read(*configPath)
	if err != nil {
		fmt.Fprintf(os.Stderr, "could not initialize clients: %s\n", err)
		os.Exit(1)
	}

	start := time.Now()

	// initialize client
	client, err := drive.NewClient(config)
	if err != nil {
		log.Fatalf("could not initialize client: %s\n", err)
	}

	// initialize the goroutines to upload chunks
	uploadRequests := make(chan chunkToGo)
	var workers sync.WaitGroup
	workers.Add(*numUploaders)
	for w := 1; w <= *numUploaders; w++ {
		go func(reqs chan chunkToGo) {
			for r := range reqs {
				numRetries := 0
				b := &backoff.Backoff{Factor: 4}
				for {
					numRetries++
					if err := client.PutChunk(r.chunk.Sha256, r.chunkbytes, r.manifest); err != nil {
						if numRetries >= *maxRetries {
							fmt.Fprintf(os.Stderr, "chunk upload failed: %s\n", err)
							os.Exit(1)
						}
						glog.Errorf("chunk write error, will retry: %s", err)
						time.Sleep(b.Duration())
						continue
					}
					b.Reset()
					break
				}
			}
			workers.Done()
			return
		}(uploadRequests)
	}

	filename := flag.Arg(0)

	manifest := shade.NewFile(flag.Arg(1))

	fh, err := os.Open(filename)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err)
		os.Exit(3)
	}

	var rt runtime.MemStats
	for {
		// Initialize chunk, to ensure each chunk uses a unique nonce
		chunk := shade.NewChunk()
		chunk.Index = len(manifest.Chunks)
		// Initialize chunkbytes, so it's safe for concurrent access later
		chunkbytes := make([]byte, manifest.Chunksize)

		// Read a chunk
		numBytes, err := fh.Read(chunkbytes)
		if err == io.EOF {
			break
		} else if err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", err)
			os.Exit(3)
		} else if len(manifest.Chunks) >= *maxChunks {
			glog.Info("Reached the maximum number of chunks in a single file.")
			break
		}
		manifest.Filesize += int64(numBytes)

		// truncate the chunkbytes array on the last read
		if numBytes < manifest.Chunksize {
			chunkbytes = chunkbytes[:numBytes]
			manifest.LastChunksize = numBytes
		}

		a := sha256.Sum256(chunkbytes)
		chunk.Sha256 = a[:]

		manifest.Chunks = append(manifest.Chunks, chunk)

		if glog.V(3) {
			if (len(manifest.Chunks) % 10) == 0 {
				runtime.ReadMemStats(&rt)
				glog.Infof("%d chunks: %0.2f MBytes Heap, %0.2f MBytes Sys\n", len(manifest.Chunks), float64(rt.Alloc)/1024/1024, float64(rt.Sys)/1024/1024)

				if glog.V(9) {
					f, err := os.Create("/tmp/throw.mprof")
					if err != nil {
						log.Fatal(err)
					}
					pprof.WriteHeapProfile(f)
					f.Close()
				}
			}
		}
		// upload the chunk
		uploadRequests <- chunkToGo{chunk, chunkbytes, manifest}
	}
	close(uploadRequests)
	workers.Wait()

	jm, err := json.Marshal(manifest)
	if err != nil {
		fmt.Fprintf(os.Stderr, "could not marshal file manifest: %s\n", err)
		os.Exit(1)
	}
	// upload the manifest
	a := sha256.Sum256(jm)
	if err := client.PutFile(a[:], jm); err != nil {
		fmt.Fprintf(os.Stderr, "manifest upload failed: %s\n", err)
		os.Exit(1)
	}

	elapsed := time.Since(start)
	size := manifest.Filesize / 1024 / 1024
	MBps := float64(size) / (float64(elapsed.Nanoseconds()) / 1000000)
	fmt.Printf("Uploaded %d MB in %s at %0.2f MB/s.\n", size, elapsed, MBps)
}
<|endoftext|>