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

// ht generates HTTP requests and checks the received responses.
//
package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"

	"github.com/vdobler/ht/ht"
)

// A Command is one of the subcommands of ht.
type Command struct {
	// Run the command.
	// The args are the arguments after the command name.
	Run func(cmd *Command, suites []*ht.Suite)

	Usage       string       // must start with command name
	Description string       // short description for ' go help'
	Help        string       // the output of 'ht help <cmd>'
	Flag        flag.FlagSet // the flags for this command
}

// Name returns the command's name: the first word in the usage line.
func (c *Command) Name() string {
	name := c.Usage
	i := strings.Index(name, " ")
	if i >= 0 {
		name = name[:i]
	}
	return name
}

func (c *Command) usage() {
	fmt.Fprintf(os.Stderr, "usage: %s\n\n", c.Usage)
	fmt.Fprintf(os.Stderr, "%s\n", c.Help)
	os.Exit(2)
}

// Commands lists the available commands and help topics.
// The order here is the order in which they are printed by 'go help'.
var commands = []*Command{
	cmdList,
	cmdRun,
	cmdExec,
	cmdBench,
	cmdPerf,
}

func usage() {
	formatedCmdList := ""

	for _, cmd := range commands {
		formatedCmdList += fmt.Sprintf("    %-8s %s\n",
			cmd.Name(), cmd.Description)
	}

	fmt.Printf(`Ht is a tool to generate http request and test the response.

Usage:

    ht <command> [flags...] <suite>...

The commands are:
%s
Run  ht help <command> to display the usage of <command>.

Tests IDs have the following format <suite>.<type><test> with <suite> and
<test> the sequential numbers of the suite and the test inside the suite.
Type is either empty, "u" for setUp test or "d" for tearDown tests. <test>
maybe a single number like "3" or a range like "3-7".
`, formatedCmdList)
	os.Exit(2)
}

// Variables which can be set via the command line. Statisfied flag.Value interface.
type cmdlVar map[string]string

func (v cmdlVar) String() string { return "" }
func (v cmdlVar) Set(s string) error {
	part := strings.SplitN(s, "=", 2)
	if len(part) != 2 {
		return fmt.Errorf("Bad argument '%s' to -D commandline parameter", s)
	}
	v[part[0]] = part[1]
	return nil
}

// Includepath which can be set via the command line. Statisfied flag.Value interface.
type cmdlIncl []string

func (i *cmdlIncl) String() string { return "" }
func (i *cmdlIncl) Set(s string) error {
	s = strings.TrimRight(s, "/")
	*i = append(*i, s)
	return nil
}

// The common flags.
var (
	variablesFlag cmdlVar = make(cmdlVar) // flag -D
	onlyFlag      string
	skipFlag      string
	verbosity     int
)

func addVariablesFlag(fs *flag.FlagSet) {
	fs.Var(variablesFlag, "D", "set `parameter=value`")
}

func addOnlyFlag(fs *flag.FlagSet) {
	fs.StringVar(&onlyFlag, "only", "", "run only tests given by `testID`")
}

func addSkipFlag(fs *flag.FlagSet) {
	fs.StringVar(&skipFlag, "skip", "", "skip tests identified by `testID`")
}

func addVerbosityFlag(fs *flag.FlagSet) {
	fs.IntVar(&verbosity, "verbosity", -99, "verbosity to `level`")
}

func main() {
	flag.Usage = usage
	flag.Parse()

	args := flag.Args()
	if len(args) < 1 {
		usage()
	}

	if args[0] == "help" {
		help(args[1:])
		return
	}
	var suites []*ht.Suite
	for _, cmd := range commands {
		if cmd.Name() == args[0] {
			cmd.Flag.Usage = func() { cmd.usage() }
			cmd.Flag.Parse(args[1:])
			args = cmd.Flag.Args()
			if cmd.Name() == "run" {
				suites = loadTests(args)
			} else {
				suites = loadSuites(args)
			}
			cmd.Run(cmd, suites)
			return
		}
	}

	fmt.Fprintf(os.Stderr, "go: unknown subcommand %q\nRun 'go help' for usage.\n",
		args[0])
	os.Exit(2)
}

// The help command.
func help(args []string) {
	if len(args) == 0 {
		usage() // TODO: this is not a failure
	}
	if len(args) != 1 {
		fmt.Fprintf(os.Stderr, "usage: ht help <command>\n\nToo many arguments given.\n")
		os.Exit(2)
	}

	arg := args[0]

	for _, cmd := range commands {
		if cmd.Name() == arg {
			fmt.Printf(`Usage:

    ht %s
%s
Flags:
`, cmd.Usage, cmd.Help)
			cmd.Flag.PrintDefaults()
			return
		}
	}

	fmt.Fprintf(os.Stderr, "Unknown help topic %#q.  Run 'ht help'.\n", arg)
	os.Exit(2) // failed at 'go help cmd'
}

func loadSuites(args []string) []*ht.Suite {
	var suites []*ht.Suite

	logger := log.New(os.Stdout, "", log.LstdFlags)

	// Handle -only and -skip flags.
	only, skip := splitTestIDs(onlyFlag), splitTestIDs(skipFlag)

	// Input and setup suites from command line arguments.
	for _, s := range args {
		suite, err := ht.LoadSuite(s)
		if err != nil {
			log.Fatalf("Cannot read suite %q: %s", s, err)
		}
		for varName, varVal := range variablesFlag {
			suite.Variables[varName] = varVal
		}
		suite.Log = logger
		err = suite.Prepare()
		if err != nil {
			log.Fatal(err.Error())
		}
		if verbosity != -99 {
			for i := range suite.Setup {
				suite.Setup[i].Verbosity = verbosity
			}
			for i := range suite.Tests {
				suite.Tests[i].Verbosity = verbosity
			}
			for i := range suite.Teardown {
				suite.Teardown[i].Verbosity = verbosity
			}
		}
		suites = append(suites, suite)
	}

	// Disable tests based on the -only and -skip flags.
	for sNo, suite := range suites {
		for tNo, test := range suite.Setup {
			shouldRun(test, fmt.Sprintf("%d.u%d", sNo+1, tNo+1), only, skip)
		}
		for tNo, test := range suite.Tests {
			shouldRun(test, fmt.Sprintf("%d.%d", sNo+1, tNo+1), only, skip)
		}
		for tNo, test := range suite.Teardown {
			shouldRun(test, fmt.Sprintf("%d.d%d", sNo+1, tNo+1), only, skip)
		}
	}

	return suites
}

// loadTests loads single Test and combines them into an artificial
// Suite, ready for execution. Unrolling happens, but only the first
// unrolled test gets included into the suite.
func loadTests(args []string) []*ht.Suite {
	logger := log.New(os.Stdout, "", log.LstdFlags)
	suite := &ht.Suite{
		Name: "Autogenerated suite for run",
		Log:  logger,
	}

	// Input and setup tests from command line arguments.
	for _, t := range args {
		tests, err := ht.LoadTest(t)
		if err != nil {
			log.Fatalf("Cannot read test %q: %s", t, err)
		}
		suite.Tests = append(suite.Tests, tests[0])
	}

	err := suite.Prepare()
	if err != nil {
		log.Fatal(err.Error())
	}
	if verbosity != -99 {
		for i := range suite.Tests {
			suite.Tests[i].Verbosity = verbosity
		}
	}

	for varName, varVal := range variablesFlag {
		suite.Variables[varName] = varVal
	}

	suites := []*ht.Suite{suite}
	return suites
}

// shouldRun disables t if needed.
func shouldRun(t *ht.Test, id string, only, skip map[string]struct{}) {
	if _, ok := skip[id]; ok {
		t.Poll.Max = -1
		log.Printf("Skipping test %s %q", id, t.Name)
		return
	}
	if _, ok := only[id]; !ok && len(only) > 0 {
		t.Poll.Max = -1
		log.Printf("Not running test %s %q", id, t.Name)
		return
	}
}

func splitTestIDs(f string) (ids map[string]struct{}) {
	ids = make(map[string]struct{})
	if len(f) == 0 {
		return
	}
	fp := strings.Split(f, ",")
	for _, x := range fp {
		xp := strings.SplitN(x, ".", 2)
		s, t := "1", xp[0]
		if len(xp) == 2 {
			s, t = xp[0], xp[1]
		}
		typ := ""
		switch t[0] {
		case 'U', 'u', 'S', 's':
			typ = "U"
			t = t[1:]
		case 'D', 'd', 'T', 't':
			typ = "D"
			t = t[1:]
		default:
			typ = ""
		}
		// TODO: support ranges like "3.1-5"
		sNo := mustAtoi(s)
		beg, end := 1, 99
		if i := strings.Index(t, "-"); i > -1 {
			if i > 0 {
				beg = mustAtoi(t[:i])
			}
			if i < len(t)-1 {
				end = mustAtoi(t[i+1:])
			}
		} else {
			beg = mustAtoi(t)
			end = beg
		}
		for tNo := beg; tNo <= end; tNo++ {
			id := fmt.Sprintf("%d.%s%d", sNo, typ, tNo)
			ids[id] = struct{}{}
		}
	}
	return ids
}

func mustAtoi(s string) int {
	n, err := strconv.Atoi(s)
	if err != nil {
		log.Fatalf("%s", err.Error())
	}
	return n
}

// add current working direcory to end of include path slice if not already
// there.
func addCWD(i *cmdlIncl) {
	for _, p := range *i {
		if p == "." {
			return
		}
	}
	*i = append(*i, ".")
}
<commit_msg>cmd/ht: fix skipping setup or teardown tests<commit_after>// Copyright 2014 Volker Dobler.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// ht generates HTTP requests and checks the received responses.
//
package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"

	"github.com/vdobler/ht/ht"
)

// A Command is one of the subcommands of ht.
type Command struct {
	// Run the command.
	// The args are the arguments after the command name.
	Run func(cmd *Command, suites []*ht.Suite)

	Usage       string       // must start with command name
	Description string       // short description for ' go help'
	Help        string       // the output of 'ht help <cmd>'
	Flag        flag.FlagSet // the flags for this command
}

// Name returns the command's name: the first word in the usage line.
func (c *Command) Name() string {
	name := c.Usage
	i := strings.Index(name, " ")
	if i >= 0 {
		name = name[:i]
	}
	return name
}

func (c *Command) usage() {
	fmt.Fprintf(os.Stderr, "usage: %s\n\n", c.Usage)
	fmt.Fprintf(os.Stderr, "%s\n", c.Help)
	os.Exit(2)
}

// Commands lists the available commands and help topics.
// The order here is the order in which they are printed by 'go help'.
var commands = []*Command{
	cmdList,
	cmdRun,
	cmdExec,
	cmdBench,
	cmdPerf,
}

func usage() {
	formatedCmdList := ""

	for _, cmd := range commands {
		formatedCmdList += fmt.Sprintf("    %-8s %s\n",
			cmd.Name(), cmd.Description)
	}

	fmt.Printf(`Ht is a tool to generate http request and test the response.

Usage:

    ht <command> [flags...] <suite>...

The commands are:
%s
Run  ht help <command> to display the usage of <command>.

Tests IDs have the following format <suite>.<type><test> with <suite> and
<test> the sequential numbers of the suite and the test inside the suite.
Type is either empty, "u" for setUp test or "d" for tearDown tests. <test>
maybe a single number like "3" or a range like "3-7".
`, formatedCmdList)
	os.Exit(2)
}

// Variables which can be set via the command line. Statisfied flag.Value interface.
type cmdlVar map[string]string

func (v cmdlVar) String() string { return "" }
func (v cmdlVar) Set(s string) error {
	part := strings.SplitN(s, "=", 2)
	if len(part) != 2 {
		return fmt.Errorf("Bad argument '%s' to -D commandline parameter", s)
	}
	v[part[0]] = part[1]
	return nil
}

// Includepath which can be set via the command line. Statisfied flag.Value interface.
type cmdlIncl []string

func (i *cmdlIncl) String() string { return "" }
func (i *cmdlIncl) Set(s string) error {
	s = strings.TrimRight(s, "/")
	*i = append(*i, s)
	return nil
}

// The common flags.
var (
	variablesFlag cmdlVar = make(cmdlVar) // flag -D
	onlyFlag      string
	skipFlag      string
	verbosity     int
)

func addVariablesFlag(fs *flag.FlagSet) {
	fs.Var(variablesFlag, "D", "set `parameter=value`")
}

func addOnlyFlag(fs *flag.FlagSet) {
	fs.StringVar(&onlyFlag, "only", "", "run only tests given by `testID`")
}

func addSkipFlag(fs *flag.FlagSet) {
	fs.StringVar(&skipFlag, "skip", "", "skip tests identified by `testID`")
}

func addVerbosityFlag(fs *flag.FlagSet) {
	fs.IntVar(&verbosity, "verbosity", -99, "verbosity to `level`")
}

func main() {
	flag.Usage = usage
	flag.Parse()

	args := flag.Args()
	if len(args) < 1 {
		usage()
	}

	if args[0] == "help" {
		help(args[1:])
		return
	}
	var suites []*ht.Suite
	for _, cmd := range commands {
		if cmd.Name() == args[0] {
			cmd.Flag.Usage = func() { cmd.usage() }
			cmd.Flag.Parse(args[1:])
			args = cmd.Flag.Args()
			if cmd.Name() == "run" {
				suites = loadTests(args)
			} else {
				suites = loadSuites(args)
			}
			cmd.Run(cmd, suites)
			return
		}
	}

	fmt.Fprintf(os.Stderr, "go: unknown subcommand %q\nRun 'go help' for usage.\n",
		args[0])
	os.Exit(2)
}

// The help command.
func help(args []string) {
	if len(args) == 0 {
		usage() // TODO: this is not a failure
	}
	if len(args) != 1 {
		fmt.Fprintf(os.Stderr, "usage: ht help <command>\n\nToo many arguments given.\n")
		os.Exit(2)
	}

	arg := args[0]

	for _, cmd := range commands {
		if cmd.Name() == arg {
			fmt.Printf(`Usage:

    ht %s
%s
Flags:
`, cmd.Usage, cmd.Help)
			cmd.Flag.PrintDefaults()
			return
		}
	}

	fmt.Fprintf(os.Stderr, "Unknown help topic %#q.  Run 'ht help'.\n", arg)
	os.Exit(2) // failed at 'go help cmd'
}

func loadSuites(args []string) []*ht.Suite {
	var suites []*ht.Suite

	logger := log.New(os.Stdout, "", log.LstdFlags)

	// Handle -only and -skip flags.
	only, skip := splitTestIDs(onlyFlag), splitTestIDs(skipFlag)

	// Input and setup suites from command line arguments.
	for _, s := range args {
		suite, err := ht.LoadSuite(s)
		if err != nil {
			log.Fatalf("Cannot read suite %q: %s", s, err)
		}
		for varName, varVal := range variablesFlag {
			suite.Variables[varName] = varVal
		}
		suite.Log = logger
		err = suite.Prepare()
		if err != nil {
			log.Fatal(err.Error())
		}
		if verbosity != -99 {
			for i := range suite.Setup {
				suite.Setup[i].Verbosity = verbosity
			}
			for i := range suite.Tests {
				suite.Tests[i].Verbosity = verbosity
			}
			for i := range suite.Teardown {
				suite.Teardown[i].Verbosity = verbosity
			}
		}
		suites = append(suites, suite)
	}

	// Disable tests based on the -only and -skip flags.
	for sNo, suite := range suites {
		for tNo, test := range suite.Setup {
			shouldRun(test, fmt.Sprintf("%d.U%d", sNo+1, tNo+1), only, skip)
		}
		for tNo, test := range suite.Tests {
			shouldRun(test, fmt.Sprintf("%d.%d", sNo+1, tNo+1), only, skip)
		}
		for tNo, test := range suite.Teardown {
			shouldRun(test, fmt.Sprintf("%d.D%d", sNo+1, tNo+1), only, skip)
		}
	}

	return suites
}

// loadTests loads single Test and combines them into an artificial
// Suite, ready for execution. Unrolling happens, but only the first
// unrolled test gets included into the suite.
func loadTests(args []string) []*ht.Suite {
	logger := log.New(os.Stdout, "", log.LstdFlags)
	suite := &ht.Suite{
		Name: "Autogenerated suite for run",
		Log:  logger,
	}

	// Input and setup tests from command line arguments.
	for _, t := range args {
		tests, err := ht.LoadTest(t)
		if err != nil {
			log.Fatalf("Cannot read test %q: %s", t, err)
		}
		suite.Tests = append(suite.Tests, tests[0])
	}

	err := suite.Prepare()
	if err != nil {
		log.Fatal(err.Error())
	}
	if verbosity != -99 {
		for i := range suite.Tests {
			suite.Tests[i].Verbosity = verbosity
		}
	}

	for varName, varVal := range variablesFlag {
		suite.Variables[varName] = varVal
	}

	suites := []*ht.Suite{suite}
	return suites
}

// shouldRun disables t if needed.
func shouldRun(t *ht.Test, id string, only, skip map[string]struct{}) {
	if _, ok := skip[id]; ok {
		t.Poll.Max = -1
		log.Printf("Skipping test %s %q", id, t.Name)
		return
	}
	if _, ok := only[id]; !ok && len(only) > 0 {
		t.Poll.Max = -1
		log.Printf("Not running test %s %q", id, t.Name)
		return
	}
}

func splitTestIDs(f string) (ids map[string]struct{}) {
	ids = make(map[string]struct{})
	if len(f) == 0 {
		return
	}
	fp := strings.Split(f, ",")
	for _, x := range fp {
		xp := strings.SplitN(x, ".", 2)
		s, t := "1", xp[0]
		if len(xp) == 2 {
			s, t = xp[0], xp[1]
		}
		typ := ""
		switch t[0] {
		case 'U', 'u', 'S', 's':
			typ = "U"
			t = t[1:]
		case 'D', 'd', 'T', 't':
			typ = "D"
			t = t[1:]
		default:
			typ = ""
		}
		// TODO: support ranges like "3.1-5"
		sNo := mustAtoi(s)
		beg, end := 1, 99
		if i := strings.Index(t, "-"); i > -1 {
			if i > 0 {
				beg = mustAtoi(t[:i])
			}
			if i < len(t)-1 {
				end = mustAtoi(t[i+1:])
			}
		} else {
			beg = mustAtoi(t)
			end = beg
		}
		for tNo := beg; tNo <= end; tNo++ {
			id := fmt.Sprintf("%d.%s%d", sNo, typ, tNo)
			ids[id] = struct{}{}
		}
	}
	return ids
}

func mustAtoi(s string) int {
	n, err := strconv.Atoi(s)
	if err != nil {
		log.Fatalf("%s", err.Error())
	}
	return n
}

// add current working direcory to end of include path slice if not already
// there.
func addCWD(i *cmdlIncl) {
	for _, p := range *i {
		if p == "." {
			return
		}
	}
	*i = append(*i, ".")
}
<|endoftext|>


<commit_before>package cmd

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

	"github.com/open-falcon/falcon-plus/g"
	"github.com/spf13/cobra"
)

var Monitor = &cobra.Command{
	Use:   "monitor [Module ...]",
	Short: "Display an Open-Falcon module's log",
	Long: `
Display the log of the specified Open-Falcon module.
A module represents a single node in a cluster.
Modules:
  ` + strings.Join(g.AllModulesInOrder, " "),
	RunE: monitor,
}

func checkMonReq(name string) error {
	if !g.HasModule(name) {
		return fmt.Errorf("%s doesn't exist", name)
	}

	if !g.HasLogfile(name) {
		r := g.Rel(g.Cfg(name))
		return fmt.Errorf("expect logfile: %s", r)
	}

	return nil
}

func monitor(c *cobra.Command, args []string) error {
	if len(args) < 1 {
		return c.Usage()
	}
	var tailArgs []string = []string{"-f"}
	for _,moduleName := range args {
		if err := checkMonReq(moduleName); err != nil {
			return err
		}

		tailArgs = append(tailArgs, g.LogPath(moduleName))
	}
	cmd := exec.Command("tail", tailArgs[0:]...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}
<commit_msg>code fix<commit_after>package cmd

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

	"github.com/open-falcon/falcon-plus/g"
	"github.com/spf13/cobra"
)

var Monitor = &cobra.Command{
	Use:   "monitor [Module ...]",
	Short: "Display an Open-Falcon module's log",
	Long: `
Display the log of the specified Open-Falcon module.
A module represents a single node in a cluster.
Modules:
  ` + strings.Join(g.AllModulesInOrder, " "),
	RunE: monitor,
}

func checkMonReq(name string) error {
	if !g.HasModule(name) {
		return fmt.Errorf("%s doesn't exist", name)
	}

	if !g.HasLogfile(name) {
		r := g.Rel(g.Cfg(name))
		return fmt.Errorf("expect logfile: %s", r)
	}

	return nil
}

func monitor(c *cobra.Command, args []string) error {
	if len(args) < 1 {
		return c.Usage()
	}
	var tailArgs []string = []string{"-f"}
	for _,moduleName := range args {
		if err := checkMonReq(moduleName); err != nil {
			return err
		}

		tailArgs = append(tailArgs, g.LogPath(moduleName))
	}
	cmd := exec.Command("tail", tailArgs...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"net/http/httputil"
	"os"

	"github.com/knq/hilink"
)

var (
	flagEndpoint = flag.String("endpoint", "http://192.168.8.1/", "api endpoint")
	flagDebug    = flag.Bool("v", false, "enable verbose")
	flagTo       = flag.String("to", "", "to")
	flagMsg      = flag.String("msg", "", "message")
	flagList     = flag.Bool("list", false, "list sms messages in inbox")
)

type httpLogger struct {
	RoundTripper http.RoundTripper
}

func (hl *httpLogger) RoundTrip(req *http.Request) (*http.Response, error) {
	reqBody, _ := httputil.DumpRequestOut(req, true)

	res, err := hl.RoundTripper.RoundTrip(req)
	resBody, _ := httputil.DumpResponse(res, true)

	fmt.Println("------------------------------")
	fmt.Printf("%s\n\n", reqBody)
	fmt.Printf("%s", resBody)
	fmt.Println("------------------------------\n\n")

	return res, err
}

func main() {
	flag.Parse()

	// setup logger
	if *flagDebug {
		http.DefaultTransport = &httpLogger{
			RoundTripper: http.DefaultTransport,
		}
	}

	// create client
	client, err := hilink.NewClient(*flagEndpoint)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}

	// handle list
	if *flagList {
		doList(client, hilink.SmsBoxTypeInbox)
		return
	}

	// check flags
	if *flagMsg == "" {
		fmt.Fprintf(os.Stderr, "error: must specify msg\n")
		os.Exit(1)
	}
	if *flagTo == "" {
		fmt.Fprintf(os.Stderr, "error: must specify to\n")
		os.Exit(1)
	}

	// send sms
	b, err := client.SmsSend(*flagMsg, *flagTo)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}
	if !b {
		fmt.Fprintf(os.Stderr, "could not send message\n")
		os.Exit(1)
	}

	fmt.Fprintf(os.Stdout, "message sent\n")
}

// doList lists the sms in the inbox in json format.
func doList(client *hilink.Client, bt hilink.SmsBoxType) {
	// get sms counts
	c, err := client.SmsCount()
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}

	buf, err := json.Marshal(c)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}

	fmt.Printf(">>> stuff: %s", string(buf))

}
<commit_msg>Fixing sms cli util<commit_after>package main

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

	"github.com/knq/hilink"
)

var (
	flagEndpoint = flag.String("endpoint", "http://192.168.8.1/", "api endpoint")
	flagDebug    = flag.Bool("v", false, "enable verbose")
	flagTo       = flag.String("to", "", "to")
	flagMsg      = flag.String("msg", "", "message")
	flagList     = flag.Bool("list", false, "list sms messages in inbox")
)

func main() {
	var err error

	flag.Parse()

	// options
	opts := []hilink.Option{
		hilink.URL(*flagEndpoint),
	}
	if *flagDebug {
		opts = append(opts, hilink.Log(log.Printf, log.Printf))
	}

	// create client
	client, err := hilink.NewClient(opts...)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}

	// handle list
	if *flagList {
		doList(client, hilink.SmsBoxTypeInbox)
		return
	}

	// check flags
	if *flagMsg == "" {
		fmt.Fprintf(os.Stderr, "error: must specify msg\n")
		os.Exit(1)
	}
	if *flagTo == "" {
		fmt.Fprintf(os.Stderr, "error: must specify to\n")
		os.Exit(1)
	}

	// send sms
	b, err := client.SmsSend(*flagMsg, *flagTo)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}
	if !b {
		fmt.Fprintf(os.Stderr, "could not send message\n")
		os.Exit(1)
	}

	fmt.Fprintf(os.Stdout, "message sent\n")
}

// doList lists the sms in the inbox in json format.
func doList(client *hilink.Client, bt hilink.SmsBoxType) {
	// get sms counts
	c, err := client.SmsCount()
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}

	buf, err := json.Marshal(c)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}

	fmt.Printf(">>> stuff: %s", string(buf))

}
<|endoftext|>


<commit_before>package widgets

import (
	"strings"

	"github.com/ambientsound/pms/index"
	"github.com/ambientsound/pms/input/parser"
	"github.com/ambientsound/pms/options"
	"github.com/ambientsound/pms/songlist"
	"github.com/ambientsound/pms/version"

	"github.com/gdamore/tcell"
	"github.com/gdamore/tcell/views"
)

type StyleMap map[string]tcell.Style

type UI struct {
	// UI elements
	App    *views.Application
	Layout *views.BoxLayout

	Topbar        *views.TextBar
	Playbar       *PlaybarWidget
	Columnheaders *ColumnheadersWidget
	Multibar      *MultibarWidget
	Songlist      *SongListWidget

	// Input events
	EventInputCommand chan string
	EventKeyInput     chan parser.KeyEvent

	// Data resources
	Index           *index.Index
	defaultSongList *songlist.SongList
	options         *options.Options

	// TCell
	view views.View
	widget
	views.WidgetWatchers
}

func NewUI(opts *options.Options) *UI {
	ui := &UI{}

	ui.EventInputCommand = make(chan string, 16)
	ui.EventKeyInput = make(chan parser.KeyEvent, 16)

	ui.App = &views.Application{}
	ui.options = opts

	ui.Topbar = views.NewTextBar()
	ui.Playbar = NewPlaybarWidget()
	ui.Columnheaders = NewColumnheadersWidget()
	ui.Multibar = NewMultibarWidget(ui.EventKeyInput)
	ui.Songlist = NewSongListWidget()

	ui.Multibar.Watch(ui)
	ui.Songlist.Watch(ui)
	ui.Playbar.Watch(ui)

	styles := StyleMap{
		"album":        tcell.StyleDefault.Foreground(tcell.ColorTeal),
		"artist":       tcell.StyleDefault.Foreground(tcell.ColorYellow),
		"commandText":  tcell.StyleDefault,
		"cursor":       tcell.StyleDefault.Background(tcell.ColorWhite).Foreground(tcell.ColorBlack),
		"date":         tcell.StyleDefault.Foreground(tcell.ColorGreen),
		"elapsed":      tcell.StyleDefault.Foreground(tcell.ColorGreen),
		"errorText":    tcell.StyleDefault.Background(tcell.ColorRed).Foreground(tcell.ColorWhite).Bold(true),
		"header":       tcell.StyleDefault.Foreground(tcell.ColorGreen).Bold(true),
		"readout":      tcell.StyleDefault,
		"searchText":   tcell.StyleDefault.Foreground(tcell.ColorWhite).Bold(true),
		"sequenceText": tcell.StyleDefault.Foreground(tcell.ColorTeal),
		"statusbar":    tcell.StyleDefault,
		"switches":     tcell.StyleDefault.Foreground(tcell.ColorTeal),
		"time":         tcell.StyleDefault.Foreground(tcell.ColorDarkMagenta),
		"title":        tcell.StyleDefault.Foreground(tcell.ColorWhite).Bold(true),
		"topbar":       tcell.StyleDefault.Foreground(tcell.ColorYellow).Bold(true),
		"track":        tcell.StyleDefault.Foreground(tcell.ColorGreen),
		"volume":       tcell.StyleDefault.Foreground(tcell.ColorGreen),
		"year":         tcell.StyleDefault.Foreground(tcell.ColorGreen),
	}

	// Styles for widgets that don't have their own class yet.
	ui.SetStyleMap(styles)
	ui.Topbar.SetStyle(ui.Style("topbar"))
	ui.Topbar.SetLeft(version.ShortName(), ui.Style("topbar"))
	ui.Topbar.SetRight(version.Version(), ui.Style("topbar"))

	ui.Columnheaders.SetStyleMap(styles)
	ui.Playbar.SetStyleMap(styles)
	ui.Songlist.SetStyleMap(styles)
	ui.Multibar.SetStyleMap(styles)

	ui.CreateLayout()
	ui.App.SetRootWidget(ui)

	return ui
}

func (ui *UI) CreateLayout() {
	ui.Layout = views.NewBoxLayout(views.Vertical)
	ui.Layout.AddWidget(ui.Topbar, 0)
	ui.Layout.AddWidget(ui.Playbar, 0)
	ui.Layout.AddWidget(ui.Columnheaders, 0)
	ui.Layout.AddWidget(ui.Songlist, 2)
	ui.Layout.AddWidget(ui.Multibar, 0)
	ui.Layout.SetView(ui.view)
}

func (ui *UI) SetIndex(i *index.Index) {
	ui.Index = i
}

func (ui *UI) SetDefaultSonglist(s *songlist.SongList) {
	ui.defaultSongList = s
}

func (ui *UI) Start() {
	ui.App.Start()
}

func (ui *UI) Wait() error {
	return ui.App.Wait()
}

func (ui *UI) Quit() {
	ui.App.Quit()
}

func (ui *UI) Draw() {
	ui.Layout.Draw()
}

func (ui *UI) Resize() {
	ui.CreateLayout()
	ui.Layout.Resize()
	ui.PostEventWidgetResize(ui)
}

func (ui *UI) SetView(v views.View) {
	ui.view = v
	ui.Layout.SetView(v)
}

func (ui *UI) Size() (int, int) {
	return ui.view.Size()
}

func (ui *UI) HandleEvent(ev tcell.Event) bool {
	switch ev := ev.(type) {

	case *tcell.EventKey:
		switch ev.Key() {
		case tcell.KeyCtrlC:
			fallthrough
		case tcell.KeyCtrlD:
			ui.App.Quit()
			return true
		case tcell.KeyCtrlL:
			ui.App.Refresh()
			return true
		}

	case *EventListChanged:
		ui.App.Update()
		ui.Topbar.SetCenter(" "+ui.Songlist.Name()+" ", ui.Style("title"))
		ui.Columnheaders.SetColumns(ui.Songlist.Columns())
		return true

	case *EventInputChanged:
		term := ui.Multibar.RuneString()
		mode := ui.Multibar.Mode()
		switch mode {
		case MultibarModeSearch:
			ui.runIndexSearch(term)
		}
		return true

	case *EventInputFinished:
		term := ui.Multibar.RuneString()
		mode := ui.Multibar.Mode()
		switch mode {
		case MultibarModeCommandInput:
			ui.EventInputCommand <- term
		case MultibarModeSearch:
			ui.runIndexSearch("")
			ui.runIndexSearch(term)
		}
		ui.Multibar.SetMode(MultibarModeCommand)
		return true

	case *EventScroll:
		ui.refreshPositionReadout()
		return true

	}

	if ui.Layout.HandleEvent(ev) {
		return true
	}

	return false
}

func (ui *UI) refreshPositionReadout() {
	str := ui.Songlist.PositionReadout()
	ui.Multibar.SetRight(str, ui.Style("readout"))
}

func (ui *UI) runIndexSearch(term string) {
	if ui.Index == nil {
		return
	}
	if len(term) == 0 {
		ui.Songlist.SetCursor(0)
		ui.Songlist.SetSongList(ui.defaultSongList)
		ui.Songlist.SetColumns(strings.Split(ui.options.StringValue("columns"), ","))
		return
	}
	if len(term) == 1 {
		return
	}
	results, err := ui.Index.Search(term)
	if err == nil {
		ui.Songlist.SetCursor(0)
		ui.Songlist.SetSongList(results)
		ui.Songlist.SetColumns(strings.Split(ui.options.StringValue("columns"), ","))
		return
	}
}
<commit_msg>Replace hard-coded C-c and C-d key events with C-c key mapping<commit_after>package widgets

import (
	"strings"

	"github.com/ambientsound/pms/index"
	"github.com/ambientsound/pms/input/parser"
	"github.com/ambientsound/pms/options"
	"github.com/ambientsound/pms/songlist"
	"github.com/ambientsound/pms/version"

	"github.com/gdamore/tcell"
	"github.com/gdamore/tcell/views"
)

type StyleMap map[string]tcell.Style

type UI struct {
	// UI elements
	App    *views.Application
	Layout *views.BoxLayout

	Topbar        *views.TextBar
	Playbar       *PlaybarWidget
	Columnheaders *ColumnheadersWidget
	Multibar      *MultibarWidget
	Songlist      *SongListWidget

	// Input events
	EventInputCommand chan string
	EventKeyInput     chan parser.KeyEvent

	// Data resources
	Index           *index.Index
	defaultSongList *songlist.SongList
	options         *options.Options

	// TCell
	view views.View
	widget
	views.WidgetWatchers
}

func NewUI(opts *options.Options) *UI {
	ui := &UI{}

	ui.EventInputCommand = make(chan string, 16)
	ui.EventKeyInput = make(chan parser.KeyEvent, 16)

	ui.App = &views.Application{}
	ui.options = opts

	ui.Topbar = views.NewTextBar()
	ui.Playbar = NewPlaybarWidget()
	ui.Columnheaders = NewColumnheadersWidget()
	ui.Multibar = NewMultibarWidget(ui.EventKeyInput)
	ui.Songlist = NewSongListWidget()

	ui.Multibar.Watch(ui)
	ui.Songlist.Watch(ui)
	ui.Playbar.Watch(ui)

	styles := StyleMap{
		"album":        tcell.StyleDefault.Foreground(tcell.ColorTeal),
		"artist":       tcell.StyleDefault.Foreground(tcell.ColorYellow),
		"commandText":  tcell.StyleDefault,
		"cursor":       tcell.StyleDefault.Background(tcell.ColorWhite).Foreground(tcell.ColorBlack),
		"date":         tcell.StyleDefault.Foreground(tcell.ColorGreen),
		"elapsed":      tcell.StyleDefault.Foreground(tcell.ColorGreen),
		"errorText":    tcell.StyleDefault.Background(tcell.ColorRed).Foreground(tcell.ColorWhite).Bold(true),
		"header":       tcell.StyleDefault.Foreground(tcell.ColorGreen).Bold(true),
		"readout":      tcell.StyleDefault,
		"searchText":   tcell.StyleDefault.Foreground(tcell.ColorWhite).Bold(true),
		"sequenceText": tcell.StyleDefault.Foreground(tcell.ColorTeal),
		"statusbar":    tcell.StyleDefault,
		"switches":     tcell.StyleDefault.Foreground(tcell.ColorTeal),
		"time":         tcell.StyleDefault.Foreground(tcell.ColorDarkMagenta),
		"title":        tcell.StyleDefault.Foreground(tcell.ColorWhite).Bold(true),
		"topbar":       tcell.StyleDefault.Foreground(tcell.ColorYellow).Bold(true),
		"track":        tcell.StyleDefault.Foreground(tcell.ColorGreen),
		"volume":       tcell.StyleDefault.Foreground(tcell.ColorGreen),
		"year":         tcell.StyleDefault.Foreground(tcell.ColorGreen),
	}

	// Styles for widgets that don't have their own class yet.
	ui.SetStyleMap(styles)
	ui.Topbar.SetStyle(ui.Style("topbar"))
	ui.Topbar.SetLeft(version.ShortName(), ui.Style("topbar"))
	ui.Topbar.SetRight(version.Version(), ui.Style("topbar"))

	ui.Columnheaders.SetStyleMap(styles)
	ui.Playbar.SetStyleMap(styles)
	ui.Songlist.SetStyleMap(styles)
	ui.Multibar.SetStyleMap(styles)

	ui.CreateLayout()
	ui.App.SetRootWidget(ui)

	return ui
}

func (ui *UI) CreateLayout() {
	ui.Layout = views.NewBoxLayout(views.Vertical)
	ui.Layout.AddWidget(ui.Topbar, 0)
	ui.Layout.AddWidget(ui.Playbar, 0)
	ui.Layout.AddWidget(ui.Columnheaders, 0)
	ui.Layout.AddWidget(ui.Songlist, 2)
	ui.Layout.AddWidget(ui.Multibar, 0)
	ui.Layout.SetView(ui.view)
}

func (ui *UI) SetIndex(i *index.Index) {
	ui.Index = i
}

func (ui *UI) SetDefaultSonglist(s *songlist.SongList) {
	ui.defaultSongList = s
}

func (ui *UI) Start() {
	ui.App.Start()
}

func (ui *UI) Wait() error {
	return ui.App.Wait()
}

func (ui *UI) Quit() {
	ui.App.Quit()
}

func (ui *UI) Draw() {
	ui.Layout.Draw()
}

func (ui *UI) Resize() {
	ui.CreateLayout()
	ui.Layout.Resize()
	ui.PostEventWidgetResize(ui)
}

func (ui *UI) SetView(v views.View) {
	ui.view = v
	ui.Layout.SetView(v)
}

func (ui *UI) Size() (int, int) {
	return ui.view.Size()
}

func (ui *UI) HandleEvent(ev tcell.Event) bool {
	switch ev := ev.(type) {

	case *tcell.EventKey:
		switch ev.Key() {
		case tcell.KeyCtrlL:
			ui.App.Refresh()
			return true
		}

	case *EventListChanged:
		ui.App.Update()
		ui.Topbar.SetCenter(" "+ui.Songlist.Name()+" ", ui.Style("title"))
		ui.Columnheaders.SetColumns(ui.Songlist.Columns())
		return true

	case *EventInputChanged:
		term := ui.Multibar.RuneString()
		mode := ui.Multibar.Mode()
		switch mode {
		case MultibarModeSearch:
			ui.runIndexSearch(term)
		}
		return true

	case *EventInputFinished:
		term := ui.Multibar.RuneString()
		mode := ui.Multibar.Mode()
		switch mode {
		case MultibarModeCommandInput:
			ui.EventInputCommand <- term
		case MultibarModeSearch:
			ui.runIndexSearch("")
			ui.runIndexSearch(term)
		}
		ui.Multibar.SetMode(MultibarModeCommand)
		return true

	case *EventScroll:
		ui.refreshPositionReadout()
		return true

	}

	if ui.Layout.HandleEvent(ev) {
		return true
	}

	return false
}

func (ui *UI) refreshPositionReadout() {
	str := ui.Songlist.PositionReadout()
	ui.Multibar.SetRight(str, ui.Style("readout"))
}

func (ui *UI) runIndexSearch(term string) {
	if ui.Index == nil {
		return
	}
	if len(term) == 0 {
		ui.Songlist.SetCursor(0)
		ui.Songlist.SetSongList(ui.defaultSongList)
		ui.Songlist.SetColumns(strings.Split(ui.options.StringValue("columns"), ","))
		return
	}
	if len(term) == 1 {
		return
	}
	results, err := ui.Index.Search(term)
	if err == nil {
		ui.Songlist.SetCursor(0)
		ui.Songlist.SetSongList(results)
		ui.Songlist.SetColumns(strings.Split(ui.options.StringValue("columns"), ","))
		return
	}
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"

	"github.com/spf13/cobra"
)

func VersionCmd() *cobra.Command {
	return &cobra.Command{
		Use:   "version",
		Short: "print the version",
		Long:  `Print the version.`,
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println("v0.2.9-beta")
		},
	}
}
<commit_msg>Version up.<commit_after>package cmd

import (
	"fmt"

	"github.com/spf13/cobra"
)

func VersionCmd() *cobra.Command {
	return &cobra.Command{
		Use:   "version",
		Short: "print the version",
		Long:  `Print the version.`,
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println("v0.2.10-beta")
		},
	}
}
<|endoftext|>


<commit_before>// Copyright © 2016 NAME HERE <EMAIL ADDRESS>
//
// 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 cmd

import (
	"fmt"

	"github.com/spf13/cobra"
)

var buildVersion = "Unknown"
var commitId string

// versionCmd represents the version command
var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Shows the version information",
	Long:  `Shows version information and exits`,
	Run: func(cmd *cobra.Command, args []string) {
		//	Show the version number
		fmt.Printf("Centralconfig version %s", buildVersion)

		//	Show the commitid if available:
		if commitId != "" {
			fmt.Printf(" (%s)", commitId[:7])
		}
	},
}

func init() {
	RootCmd.AddCommand(versionCmd)
}
<commit_msg>Updated version display<commit_after>// Copyright © 2016 NAME HERE <EMAIL ADDRESS>
//
// 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 cmd

import (
	"fmt"

	"github.com/spf13/cobra"
)

var buildVersion = "Unknown"
var commitId string

// versionCmd represents the version command
var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Shows the version information",
	Long:  `Shows version information and exits`,
	Run: func(cmd *cobra.Command, args []string) {
		//	Show the version number
		fmt.Printf("\nCentralconfig version %s\n\n", buildVersion)

		//	Show the commitid if available:
		if commitId != "" {
			fmt.Printf(" (%s)", commitId[:7])
		}
	},
}

func init() {
	RootCmd.AddCommand(versionCmd)
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"

	"github.com/spf13/cobra"
)

// version is a version number.
var version = "0.4.1"

func init() {
	RootCmd.AddCommand(newVersionCmd())
}

func newVersionCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "version",
		Short: "Print version",
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Printf("%s\n", version)
		},
	}

	return cmd
}
<commit_msg>Bump version to v0.4.2<commit_after>package cmd

import (
	"fmt"

	"github.com/spf13/cobra"
)

// version is a version number.
var version = "0.4.2"

func init() {
	RootCmd.AddCommand(newVersionCmd())
}

func newVersionCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "version",
		Short: "Print version",
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Printf("%s\n", version)
		},
	}

	return cmd
}
<|endoftext|>


<commit_before>// Copyright © 2017 Igor Bondarenko <ibondare@protonmail.com>
// 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 cmd

import (
	"fmt"

	"github.com/spf13/cobra"
)

const Version =  "0.1"

// logCmd represents the log command
var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Print the version number",
	Long: `Print httpr version number`,
	Run: executeVersion,
}

func init() {
	RootCmd.AddCommand(versionCmd)
}

func executeVersion(cmd *cobra.Command, args []string) {
	fmt.Printf("httr (HTTP Rake) version %s\n", Version)
}
<commit_msg>Fixed for proper semantic versioning<commit_after>// Copyright © 2017 Igor Bondarenko <ibondare@protonmail.com>
// 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 cmd

import (
	"fmt"

	"github.com/spf13/cobra"
)

const Version =  "0.1.0"

// logCmd represents the log command
var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Print the version number",
	Long: `Print httpr version number`,
	Run: executeVersion,
}

func init() {
	RootCmd.AddCommand(versionCmd)
}

func executeVersion(cmd *cobra.Command, args []string) {
	fmt.Printf("httr (HTTP Rake) version %s\n", Version)
}
<|endoftext|>


<commit_before>package cmd

import "github.com/spf13/cobra"

func init() {
	RootCmd.AddCommand(versionCmd)
}

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Displays the version of mbt",
	Run: func(cmd *cobra.Command, args []string) {
		println("0.1.21")
	},
}
<commit_msg>Bump version<commit_after>package cmd

import "github.com/spf13/cobra"

func init() {
	RootCmd.AddCommand(versionCmd)
}

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Displays the version of mbt",
	Run: func(cmd *cobra.Command, args []string) {
		println("0.1.22")
	},
}
<|endoftext|>


<commit_before>package main

var CmdCurrent = &Cmd{
	Name:    "current",
	Desc:    "Reports whether direnv's view of a file is current (or stale)",
	Args:    []string{"PATH"},
	Private: true,
	Fn:      currentCommandFn,
}

func currentCommandFn(env Env, args []string) (err error) {
	path := args[1]
	watches := NewFileTimes()
	watchString, ok := env[DIRENV_WATCHES]
	if ok {
		watches.Unmarshal(watchString)
	}

	err = watches.CheckOne(path)

	return
}
<commit_msg>Handle `direnv current` with no argument<commit_after>package main

import (
	"errors"
)

var CmdCurrent = &Cmd{
	Name:    "current",
	Desc:    "Reports whether direnv's view of a file is current (or stale)",
	Args:    []string{"PATH"},
	Private: true,
	Fn:      currentCommandFn,
}

func currentCommandFn(env Env, args []string) (err error) {
	if len(args) < 2 {
		err = errors.New("Missing PATH argument")
		return
	}

	path := args[1]
	watches := NewFileTimes()
	watchString, ok := env[DIRENV_WATCHES]
	if ok {
		watches.Unmarshal(watchString)
	}

	err = watches.CheckOne(path)

	return
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/gonuts/commander"
	"github.com/gonuts/flag"
)

func hwaf_make_cmd_version() *commander.Command {
	cmd := &commander.Command{
		Run:       hwaf_run_cmd_version,
		UsageLine: "version",
		Short:     "print version and exit",
		Long: `
print version and exit.

ex:
 $ hwaf version
 hwaf-20130809 (fd0bfc4)
`,
		Flag: *flag.NewFlagSet("hwaf-version", flag.ExitOnError),
	}
	return cmd
}

func hwaf_run_cmd_version(cmd *commander.Command, args []string) {
	fmt.Printf("hwaf-20130809 (fd0bfc4)\n")
}

// EOF
<commit_msg>version: 20130809<commit_after>package main

import (
	"fmt"

	"github.com/gonuts/commander"
	"github.com/gonuts/flag"
)

func hwaf_make_cmd_version() *commander.Command {
	cmd := &commander.Command{
		Run:       hwaf_run_cmd_version,
		UsageLine: "version",
		Short:     "print version and exit",
		Long: `
print version and exit.

ex:
 $ hwaf version
 hwaf-20130809 (3ee5162)
`,
		Flag: *flag.NewFlagSet("hwaf-version", flag.ExitOnError),
	}
	return cmd
}

func hwaf_run_cmd_version(cmd *commander.Command, args []string) {
	fmt.Printf("hwaf-20130809 (3ee5162)\n")
}

// EOF
<|endoftext|>


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

package build

import (
	"fmt"
	"net/http"

	"appengine"
	"appengine/datastore"
	"cache"
)

// defaultPackages specifies the Package records to be created by initHandler.
var defaultPackages = []*Package{
	{Name: "Go", Kind: "go"},
}

// subRepos specifies the Go project sub-repositories.
var subRepos = []string{
	"blog",
	"codereview",
	"crypto",
	"exp",
	"image",
	"net",
	"talks",
}

// Put subRepos into defaultPackages.
func init() {
	for _, name := range subRepos {
		p := &Package{
			Kind: "subrepo",
			Name: "go." + name,
			Path: "code.google.com/p/go." + name,
		}
		defaultPackages = append(defaultPackages, p)
	}
}

func initHandler(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	defer cache.Tick(c)
	for _, p := range defaultPackages {
		err := datastore.Get(c, p.Key(c), new(Package))
		if _, ok := err.(*datastore.ErrFieldMismatch); ok {
			// Some fields have been removed, so it's okay to ignore this error.
			err = nil
		}
		if err == nil {
			continue
		} else if err != datastore.ErrNoSuchEntity {
			logErr(w, r, err)
			return
		}
		if _, err := datastore.Put(c, p.Key(c), p); err != nil {
			logErr(w, r, err)
			return
		}
	}
	fmt.Fprint(w, "OK")
}
<commit_msg>misc/dashboard: add go.tools to list of subrepos<commit_after>// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package build

import (
	"fmt"
	"net/http"

	"appengine"
	"appengine/datastore"
	"cache"
)

// defaultPackages specifies the Package records to be created by initHandler.
var defaultPackages = []*Package{
	{Name: "Go", Kind: "go"},
}

// subRepos specifies the Go project sub-repositories.
var subRepos = []string{
	"blog",
	"codereview",
	"crypto",
	"exp",
	"image",
	"net",
	"talks",
	"tools",
}

// Put subRepos into defaultPackages.
func init() {
	for _, name := range subRepos {
		p := &Package{
			Kind: "subrepo",
			Name: "go." + name,
			Path: "code.google.com/p/go." + name,
		}
		defaultPackages = append(defaultPackages, p)
	}
}

func initHandler(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	defer cache.Tick(c)
	for _, p := range defaultPackages {
		err := datastore.Get(c, p.Key(c), new(Package))
		if _, ok := err.(*datastore.ErrFieldMismatch); ok {
			// Some fields have been removed, so it's okay to ignore this error.
			err = nil
		}
		if err == nil {
			continue
		} else if err != datastore.ErrNoSuchEntity {
			logErr(w, r, err)
			return
		}
		if _, err := datastore.Put(c, p.Key(c), p); err != nil {
			logErr(w, r, err)
			return
		}
	}
	fmt.Fprint(w, "OK")
}
<|endoftext|>


<commit_before>package backend

import (
	"errors"
	"imperial-splendour-bundler/backend/customErrors"
	"strings"
)

func (a *API) prepareModFiles(sourcePath, fileListPath string) error {
	actualFileList, err := a.Sh.GetDirContentByName(sourcePath)
	if err != nil {
		return a.error("Cannot read dir under"+sourcePath+": "+err.Error(), customErrors.ReadSourceDir)
	}
	expectedFileList, err := a.readFileList(fileListPath)
	if err != nil {
		return err
	}

	if err := a.compareFileLists(expectedFileList, actualFileList); err != nil {
		return err
	}
	a.logToFrontend("All mod files are accounted for.")
	if err := a.moveFilesIntoModFolder(sourcePath, expectedFileList); err != nil {
		return err
	}
	a.logToFrontend("Mod files were moved to mod folder.")
	if err := a.saveFileListIntoModFolder(expectedFileList); err != nil {
		return err
	}
	a.logToFrontend("File list was added to mod folder.")
	return nil
}

func (a *API) readFileList(fileListPath string) ([]string, error) {
	expectedListBlob, err := a.Sh.ReadFile(fileListPath)
	if err != nil {
		return nil, a.error("Cannot read file list: "+err.Error(), customErrors.ReadFileList)
	}
	expectedList := strings.Split(string(expectedListBlob), "\n")
	return expectedList, nil
}

func GetDifference(a, b []string) (diff []string) {
	m := make(map[string]bool)

	// set values in b as keys in the map
	for _, item := range b {
		m[item] = true
	}

	// check that values in a are keys in the map
	for _, itemInA := range a {
		if _, isKey := m[itemInA]; !isKey {
			diff = append(diff, itemInA)
		}
	}
	return diff
}

func (a *API) compareFileLists(expected, actual []string) error {
	valuesInExpectedButNotInActual := GetDifference(expected, actual)
	if len(valuesInExpectedButNotInActual) != 0 {
		missingFiles := strings.Join(valuesInExpectedButNotInActual, ", ")
		return a.error("Couldn't find the following files: "+missingFiles, errors.New(customErrors.FileMissing.Error()+" "+missingFiles))
	}
	return nil
}

func (a *API) moveFilesIntoModFolder(sourcePath string, fileList []string) error {
	for _, file := range fileList {
		source := sourcePath + file
		destination := a.setupBaseFolder + tempPath + modPath + file

		a.logToFrontend("Moving from " + source + " to " + destination)
		err := a.Sh.MoveFile(source, destination)
		if err != nil {
			return a.error("Couldn't move "+file, errors.New(customErrors.MoveFile.Error()+" "+file))
		}
	}

	return nil
}

func (a *API) saveFileListIntoModFolder(fileList []string) error {
	destination := a.setupBaseFolder + tempPath + modPath + fileListFile

	fileListByteSlice := []byte(strings.Join(fileList, "\n"))

	err := a.Sh.WriteFile(destination, fileListByteSlice)
	if err != nil {
		return a.error("Couldn't save file list: "+err.Error(), customErrors.SaveFileList)
	}
	return nil
}
<commit_msg>Improve log message<commit_after>package backend

import (
	"errors"
	"imperial-splendour-bundler/backend/customErrors"
	"strings"
)

func (a *API) prepareModFiles(sourcePath, fileListPath string) error {
	actualFileList, err := a.Sh.GetDirContentByName(sourcePath)
	if err != nil {
		return a.error("Cannot read dir under"+sourcePath+": "+err.Error(), customErrors.ReadSourceDir)
	}
	expectedFileList, err := a.readFileList(fileListPath)
	if err != nil {
		return err
	}

	if err := a.compareFileLists(expectedFileList, actualFileList); err != nil {
		return err
	}
	a.logToFrontend("All mod files are accounted for.")
	if err := a.moveFilesIntoModFolder(sourcePath, expectedFileList); err != nil {
		return err
	}
	a.logToFrontend("All mod files were moved to mod folder.")
	if err := a.saveFileListIntoModFolder(expectedFileList); err != nil {
		return err
	}
	a.logToFrontend("File list was added to mod folder.")
	return nil
}

func (a *API) readFileList(fileListPath string) ([]string, error) {
	expectedListBlob, err := a.Sh.ReadFile(fileListPath)
	if err != nil {
		return nil, a.error("Cannot read file list: "+err.Error(), customErrors.ReadFileList)
	}
	expectedList := strings.Split(string(expectedListBlob), "\n")
	return expectedList, nil
}

func GetDifference(a, b []string) (diff []string) {
	m := make(map[string]bool)

	// set values in b as keys in the map
	for _, item := range b {
		m[item] = true
	}

	// check that values in a are keys in the map
	for _, itemInA := range a {
		if _, isKey := m[itemInA]; !isKey {
			diff = append(diff, itemInA)
		}
	}
	return diff
}

func (a *API) compareFileLists(expected, actual []string) error {
	valuesInExpectedButNotInActual := GetDifference(expected, actual)
	if len(valuesInExpectedButNotInActual) != 0 {
		missingFiles := strings.Join(valuesInExpectedButNotInActual, ", ")
		return a.error("Couldn't find the following files: "+missingFiles, errors.New(customErrors.FileMissing.Error()+" "+missingFiles))
	}
	return nil
}

func (a *API) moveFilesIntoModFolder(sourcePath string, fileList []string) error {
	for _, file := range fileList {
		source := sourcePath + file
		destination := a.setupBaseFolder + tempPath + modPath + file

		a.logToFrontend("Moving from " + source + " to " + destination)
		err := a.Sh.MoveFile(source, destination)
		if err != nil {
			return a.error("Couldn't move "+file, errors.New(customErrors.MoveFile.Error()+" "+file))
		}
	}

	return nil
}

func (a *API) saveFileListIntoModFolder(fileList []string) error {
	destination := a.setupBaseFolder + tempPath + modPath + fileListFile

	fileListByteSlice := []byte(strings.Join(fileList, "\n"))

	err := a.Sh.WriteFile(destination, fileListByteSlice)
	if err != nil {
		return a.error("Couldn't save file list: "+err.Error(), customErrors.SaveFileList)
	}
	return nil
}
<|endoftext|>


<commit_before>package scp

// thanks to this for inspiration ... https://gist.github.com/jedy/3357393

import (
	"code.google.com/p/go.crypto/ssh"
	"errors"
	"flag"
	"fmt"
	"github.com/howeyc/gopass"
	"github.com/laher/uggo"
	"io"
	"os"
	"os/user"
	"strings"
)

type ScpOptions struct {
	Port         *int
	IsRecursive  *bool
	IsRemoteTo   *bool
	IsRemoteFrom *bool
}

type clientPassword string

func (p clientPassword) Password(user string) (string, error) {
	return string(p), nil
}

//TODO: error for multiple ats or multiple colons
func parseTarget(target string) (string, string, string, error) {
	if strings.Contains(target, ":") {
		//remote
		parts := strings.Split(target, ":")
		userHost := parts[0]
		file := parts[1]
		user := ""
		var host string
		if strings.Contains(userHost, "@") {
			uhParts := strings.Split(userHost, "@")
			user = uhParts[0]
			host = uhParts[1]
		} else {
			host = userHost
		}
		return file, host, user, nil
	} else {
		//local
		return target, "", "", nil
	}
}

func Scp(call []string) error {
	options := ScpOptions{}
	flagSet := flag.NewFlagSet("scp", flag.ContinueOnError)
	options.IsRecursive = flagSet.Bool("r", false, "TODO - Recursive copy")
	options.Port = flagSet.Int("P", 22, "Port number")
	options.IsRemoteTo = flagSet.Bool("t", false, "Remote 'to' mode - not currently supported")
	options.IsRemoteFrom = flagSet.Bool("f", false, "Remote 'from' mode - not currently supported")
	helpFlag := flagSet.Bool("help", false, "Show this help")
	err := flagSet.Parse(uggo.Gnuify(call[1:]))
	if err != nil {
		println("Error parsing flags")
		return err
	}
	if *options.IsRecursive {
		//return errors.New("This scp does NOT implement 'recursive scp'. Yet.")
	}
	if *options.IsRemoteTo || *options.IsRemoteFrom {
		return errors.New("This scp does NOT implement 'remote scp'. Yet.")
	}
	args := flagSet.Args()
	if *helpFlag || len(args) != 2 {
		println("`scp` [options] [[user@]host1:]file1 [[user@]host2:]file2")
		flagSet.PrintDefaults()
		return nil
	}

	srcFile, srcHost, srcUser, err := parseTarget(args[0])
	if err != nil {
		println("Error parsing source")
		return err
	}
	dstFile, dstHost, dstUser, err := parseTarget(args[1])
	if err != nil {
		println("Error parsing destination")
		return err
	}
	if srcHost != "" && dstHost != "" {
		return errors.New("remote->remote NOT implemented (yet)!")
	} else if srcHost != "" {
		err = scpFromRemote(srcUser, srcHost, srcFile, dstFile, options)
		if err != nil {
			println("Failed to run 'from-remote' scp: " + err.Error())
		}
		return err

	} else if dstHost != "" {
		err = scpToRemote(srcFile, dstUser, dstHost, dstFile, options)
		if err != nil {
			println("Failed to run 'to-remote' scp: " + err.Error())
		}
		return err
	} else {
		srcReader, err := os.Open(srcFile)
		defer srcReader.Close()
		if err != nil {
			println("Failed to open local source file ('local-local' scp): " + err.Error())
			return err
		}
		dstWriter, err := os.OpenFile(dstFile, os.O_CREATE | os.O_WRONLY, 0777)
		defer dstWriter.Close()
		if err != nil {
			println("Failed to open local destination file ('local-local' scp): " + err.Error())
			return err
		}
		n, err := io.Copy(dstWriter, srcReader)
		fmt.Printf("wrote %d bytes\n", n)
		if err != nil {
			println("Failed to run 'local-local' copy: " + err.Error())
			return err
		}
		err = dstWriter.Close()
		return err
	}
	return nil
}
func sendByte(w io.Writer, val byte) error {
	_, err := w.Write([]byte{val})
	return err
}

func connect(userName, host string, port int) (*ssh.Session, error) {
	if userName == "" {
		u, err := user.Current()
		userName = u.Username
		if err != nil {
			return nil, err
		}
	}
	fmt.Printf("%s@%s's password:", userName, host)
	pass := gopass.GetPasswd()
	password := clientPassword(pass)
	clientConfig := &ssh.ClientConfig{
		User: userName,
		Auth: []ssh.ClientAuth{
			ssh.ClientAuthPassword(password),
		},
	}
	target := fmt.Sprintf("%s:%d", host, port)
	client, err := ssh.Dial("tcp", target, clientConfig)
	if err != nil {
		println("Failed to dial: " + err.Error())
		return nil, err
	}
	session, err := client.NewSession()
	if err != nil {
		println("Failed to create session: " + err.Error())
	} else {
		println("Got session")
	}
	return session, err

}
<commit_msg>Recursive scp is done (for remote->local and local->remote)<commit_after>package scp

// thanks to this for inspiration ... https://gist.github.com/jedy/3357393

import (
	"code.google.com/p/go.crypto/ssh"
	"errors"
	"flag"
	"fmt"
	"github.com/howeyc/gopass"
	"github.com/laher/uggo"
	"io"
	"os"
	"os/user"
	"strings"
)

type ScpOptions struct {
	Port         *int
	IsRecursive  *bool
	IsRemoteTo   *bool
	IsRemoteFrom *bool
}

type clientPassword string

func (p clientPassword) Password(user string) (string, error) {
	return string(p), nil
}

//TODO: error for multiple ats or multiple colons
func parseTarget(target string) (string, string, string, error) {
	if strings.Contains(target, ":") {
		//remote
		parts := strings.Split(target, ":")
		userHost := parts[0]
		file := parts[1]
		user := ""
		var host string
		if strings.Contains(userHost, "@") {
			uhParts := strings.Split(userHost, "@")
			user = uhParts[0]
			host = uhParts[1]
		} else {
			host = userHost
		}
		return file, host, user, nil
	} else {
		//local
		return target, "", "", nil
	}
}

func Scp(call []string) error {
	options := ScpOptions{}
	flagSet := flag.NewFlagSet("scp", flag.ContinueOnError)
	options.IsRecursive = flagSet.Bool("r", false, "Recursive copy")
	options.Port = flagSet.Int("P", 22, "Port number")
	options.IsRemoteTo = flagSet.Bool("t", false, "Remote 'to' mode - not currently supported")
	options.IsRemoteFrom = flagSet.Bool("f", false, "Remote 'from' mode - not currently supported")
	helpFlag := flagSet.Bool("help", false, "Show this help")
	err := flagSet.Parse(uggo.Gnuify(call[1:]))
	if err != nil {
		println("Error parsing flags")
		return err
	}
	if *options.IsRecursive {
		//return errors.New("This scp does NOT implement 'recursive scp'. Yet.")
	}
	if *options.IsRemoteTo || *options.IsRemoteFrom {
		return errors.New("This scp does NOT implement 'remote scp'. Yet.")
	}
	args := flagSet.Args()
	if *helpFlag || len(args) != 2 {
		println("`scp` [options] [[user@]host1:]file1 [[user@]host2:]file2")
		flagSet.PrintDefaults()
		return nil
	}

	srcFile, srcHost, srcUser, err := parseTarget(args[0])
	if err != nil {
		println("Error parsing source")
		return err
	}
	dstFile, dstHost, dstUser, err := parseTarget(args[1])
	if err != nil {
		println("Error parsing destination")
		return err
	}
	if srcHost != "" && dstHost != "" {
		return errors.New("remote->remote NOT implemented (yet)!")
	} else if srcHost != "" {
		err = scpFromRemote(srcUser, srcHost, srcFile, dstFile, options)
		if err != nil {
			println("Failed to run 'from-remote' scp: " + err.Error())
		}
		return err

	} else if dstHost != "" {
		err = scpToRemote(srcFile, dstUser, dstHost, dstFile, options)
		if err != nil {
			println("Failed to run 'to-remote' scp: " + err.Error())
		}
		return err
	} else {
		srcReader, err := os.Open(srcFile)
		defer srcReader.Close()
		if err != nil {
			println("Failed to open local source file ('local-local' scp): " + err.Error())
			return err
		}
		dstWriter, err := os.OpenFile(dstFile, os.O_CREATE | os.O_WRONLY, 0777)
		defer dstWriter.Close()
		if err != nil {
			println("Failed to open local destination file ('local-local' scp): " + err.Error())
			return err
		}
		n, err := io.Copy(dstWriter, srcReader)
		fmt.Printf("wrote %d bytes\n", n)
		if err != nil {
			println("Failed to run 'local-local' copy: " + err.Error())
			return err
		}
		err = dstWriter.Close()
		return err
	}
	return nil
}
func sendByte(w io.Writer, val byte) error {
	_, err := w.Write([]byte{val})
	return err
}

func connect(userName, host string, port int) (*ssh.Session, error) {
	if userName == "" {
		u, err := user.Current()
		userName = u.Username
		if err != nil {
			return nil, err
		}
	}
	fmt.Printf("%s@%s's password:", userName, host)
	pass := gopass.GetPasswd()
	password := clientPassword(pass)
	clientConfig := &ssh.ClientConfig{
		User: userName,
		Auth: []ssh.ClientAuth{
			ssh.ClientAuthPassword(password),
		},
	}
	target := fmt.Sprintf("%s:%d", host, port)
	client, err := ssh.Dial("tcp", target, clientConfig)
	if err != nil {
		println("Failed to dial: " + err.Error())
		return nil, err
	}
	session, err := client.NewSession()
	if err != nil {
		println("Failed to create session: " + err.Error())
	} else {
		println("Got session")
	}
	return session, err

}
<|endoftext|>


<commit_before>//go:build !linux
// +build !linux

package archive

import (
	"fmt"
	"io/fs"
	"os"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/containers/storage/pkg/idtools"
	"github.com/containers/storage/pkg/system"
)

func collectFileInfoForChanges(oldDir, newDir string, oldIDMap, newIDMap *idtools.IDMappings) (*FileInfo, *FileInfo, error) {
	var (
		oldRoot, newRoot *FileInfo
		err1, err2       error
		errs             = make(chan error, 2)
	)
	go func() {
		oldRoot, err1 = collectFileInfo(oldDir, oldIDMap)
		errs <- err1
	}()
	go func() {
		newRoot, err2 = collectFileInfo(newDir, newIDMap)
		errs <- err2
	}()

	// block until both routines have returned
	for i := 0; i < 2; i++ {
		if err := <-errs; err != nil {
			return nil, nil, err
		}
	}

	return oldRoot, newRoot, nil
}

func collectFileInfo(sourceDir string, idMappings *idtools.IDMappings) (*FileInfo, error) {
	root := newRootFileInfo(idMappings)

	err := filepath.WalkDir(sourceDir, func(path string, d fs.DirEntry, err error) error {
		if err != nil {
			return err
		}

		// Rebase path
		relPath, err := filepath.Rel(sourceDir, path)
		if err != nil {
			return err
		}

		// As this runs on the daemon side, file paths are OS specific.
		relPath = filepath.Join(string(os.PathSeparator), relPath)

		// See https://github.com/golang/go/issues/9168 - bug in filepath.Join.
		// Temporary workaround. If the returned path starts with two backslashes,
		// trim it down to a single backslash. Only relevant on Windows.
		if runtime.GOOS == "windows" {
			if strings.HasPrefix(relPath, `\\`) {
				relPath = relPath[1:]
			}
		}

		if relPath == string(os.PathSeparator) {
			return nil
		}

		parent := root.LookUp(filepath.Dir(relPath))
		if parent == nil {
			return fmt.Errorf("collectFileInfo: Unexpectedly no parent for %s", relPath)
		}

		info := &FileInfo{
			name:       filepath.Base(relPath),
			children:   make(map[string]*FileInfo),
			parent:     parent,
			idMappings: idMappings,
		}

		s, err := system.Lstat(path)
		if err != nil {
			return err
		}
		info.stat = s

		info.capability, _ = system.Lgetxattr(path, "security.capability")

		parent.children[info.name] = info

		return nil
	})
	if err != nil {
		return nil, err
	}
	return root, nil
}
<commit_msg>Don't cross filesystem boundaries in ChangesDirs<commit_after>//go:build !linux
// +build !linux

package archive

import (
	"fmt"
	"io/fs"
	"os"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/containers/storage/pkg/idtools"
	"github.com/containers/storage/pkg/system"
)

func collectFileInfoForChanges(oldDir, newDir string, oldIDMap, newIDMap *idtools.IDMappings) (*FileInfo, *FileInfo, error) {
	var (
		oldRoot, newRoot *FileInfo
		err1, err2       error
		errs             = make(chan error, 2)
	)
	go func() {
		oldRoot, err1 = collectFileInfo(oldDir, oldIDMap)
		errs <- err1
	}()
	go func() {
		newRoot, err2 = collectFileInfo(newDir, newIDMap)
		errs <- err2
	}()

	// block until both routines have returned
	for i := 0; i < 2; i++ {
		if err := <-errs; err != nil {
			return nil, nil, err
		}
	}

	return oldRoot, newRoot, nil
}

func collectFileInfo(sourceDir string, idMappings *idtools.IDMappings) (*FileInfo, error) {
	root := newRootFileInfo(idMappings)

	sourceStat, err := system.Lstat(sourceDir)
	if err != nil {
		return nil, err
	}

	err = filepath.WalkDir(sourceDir, func(path string, d fs.DirEntry, err error) error {
		if err != nil {
			return err
		}

		// Rebase path
		relPath, err := filepath.Rel(sourceDir, path)
		if err != nil {
			return err
		}

		// As this runs on the daemon side, file paths are OS specific.
		relPath = filepath.Join(string(os.PathSeparator), relPath)

		// See https://github.com/golang/go/issues/9168 - bug in filepath.Join.
		// Temporary workaround. If the returned path starts with two backslashes,
		// trim it down to a single backslash. Only relevant on Windows.
		if runtime.GOOS == "windows" {
			if strings.HasPrefix(relPath, `\\`) {
				relPath = relPath[1:]
			}
		}

		if relPath == string(os.PathSeparator) {
			return nil
		}

		parent := root.LookUp(filepath.Dir(relPath))
		if parent == nil {
			return fmt.Errorf("collectFileInfo: Unexpectedly no parent for %s", relPath)
		}

		info := &FileInfo{
			name:       filepath.Base(relPath),
			children:   make(map[string]*FileInfo),
			parent:     parent,
			idMappings: idMappings,
		}

		s, err := system.Lstat(path)
		if err != nil {
			return err
		}

		if s.Dev() != sourceStat.Dev() {
			return filepath.SkipDir
		}

		info.stat = s
		info.capability, _ = system.Lgetxattr(path, "security.capability")

		parent.children[info.name] = info

		return nil
	})
	if err != nil {
		return nil, err
	}
	return root, nil
}
<|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 controller

import (
	"github.com/golang/glog"
	"github.com/jcmoraisjr/haproxy-ingress/pkg/common/ingress"
	"github.com/jcmoraisjr/haproxy-ingress/pkg/common/ingress/controller"
	"github.com/jcmoraisjr/haproxy-ingress/pkg/common/ingress/defaults"
	"github.com/jcmoraisjr/haproxy-ingress/pkg/types"
	"github.com/jcmoraisjr/haproxy-ingress/pkg/version"
	"github.com/spf13/pflag"
	"io/ioutil"
	api "k8s.io/api/core/v1"
	extensions "k8s.io/api/extensions/v1beta1"
	"net/http"
	"os"
	"os/exec"
	"strings"
	"time"
	"sort"
)

// HAProxyController has internal data of a HAProxyController instance
type HAProxyController struct {
	controller     *controller.GenericController
	configMap      *api.ConfigMap
	storeLister    *ingress.StoreLister
	command        string
	reloadStrategy *string
	configDir     string
	configFilePrefix     string
	configFileSuffix     string
	maxOldConfigFiles     *int
	template       *template
	currentConfig  *types.ControllerConfig
}

// NewHAProxyController constructor
func NewHAProxyController() *HAProxyController {
	return &HAProxyController{}
}

// Info provides controller name and repository infos
func (haproxy *HAProxyController) Info() *ingress.BackendInfo {
	return &ingress.BackendInfo{
		Name:       "HAProxy",
		Release:    version.RELEASE,
		Build:      version.COMMIT,
		Repository: version.REPO,
	}
}

// Start starts the controller
func (haproxy *HAProxyController) Start() {
	haproxy.controller = controller.NewIngressController(haproxy)
	haproxy.controller.Start()
}

// Stop shutdown the controller process
func (haproxy *HAProxyController) Stop() error {
	err := haproxy.controller.Stop()
	return err
}

// Name provides the complete name of the controller
func (haproxy *HAProxyController) Name() string {
	return "HAProxy Ingress Controller"
}

// DefaultIngressClass returns the ingress class name
func (haproxy *HAProxyController) DefaultIngressClass() string {
	return "haproxy"
}

// Check health check implementation
func (haproxy *HAProxyController) Check(_ *http.Request) error {
	return nil
}

// SetListers give access to the store listers
func (haproxy *HAProxyController) SetListers(lister *ingress.StoreLister) {
	haproxy.storeLister = lister
}

// UpdateIngressStatus custom callback used to update the status in an Ingress rule
// If the function returns nil the standard functions will be executed.
func (haproxy *HAProxyController) UpdateIngressStatus(*extensions.Ingress) []api.LoadBalancerIngress {
	return nil
}

// ConfigureFlags allow to configure more flags before the parsing of
// command line arguments
func (haproxy *HAProxyController) ConfigureFlags(flags *pflag.FlagSet) {
	haproxy.reloadStrategy = flags.String("reload-strategy", "native",
		`Name of the reload strategy. Options are: native (default), reusesocket or multibinder`)
	haproxy.maxOldConfigFiles = flags.Int("max-old-config-files", 0,
		`Maximum old haproxy timestamped config files to allow before being cleaned up. A value <= 0 indicates a single non-timestamped config file will be used`)
	ingressClass := flags.Lookup("ingress-class")
	if ingressClass != nil {
		ingressClass.Value.Set("haproxy")
		ingressClass.DefValue = "haproxy"
	}
}

// OverrideFlags allows controller to override command line parameter flags
func (haproxy *HAProxyController) OverrideFlags(flags *pflag.FlagSet) {
	haproxy.configDir = "/etc/haproxy"
	haproxy.configFilePrefix = "haproxy"
	haproxy.configFileSuffix = ".cfg"

	if !(*haproxy.reloadStrategy == "native" || *haproxy.reloadStrategy == "reusesocket" || *haproxy.reloadStrategy == "multibinder") {
		glog.Fatalf("Unsupported reload strategy: %v", *haproxy.reloadStrategy)
	}

	if *haproxy.reloadStrategy == "multibinder" {
		haproxy.template = newTemplate("haproxy.cfg.erb.tmpl", "/etc/haproxy/haproxy.cfg.erb.tmpl")
	} else {
		haproxy.template = newTemplate("haproxy.tmpl", "/etc/haproxy/template/haproxy.tmpl")
	}
	haproxy.command = "/haproxy-reload.sh"
}

// SetConfig receives the ConfigMap the user has configured
func (haproxy *HAProxyController) SetConfig(configMap *api.ConfigMap) {
	haproxy.configMap = configMap
}

// BackendDefaults defines default values to the ingress core
func (haproxy *HAProxyController) BackendDefaults() defaults.Backend {
	return newHAProxyConfig(haproxy).Backend
}

// DefaultEndpoint returns the Endpoint to use as default when the
// referenced service does not exists
func (haproxy *HAProxyController) DefaultEndpoint() ingress.Endpoint {
	return ingress.Endpoint{
		Address: "127.0.0.1",
		Port:    "8181",
		Draining:false,
		Target:  &api.ObjectReference{},
	}
}

// Indicates whether or not this controller supports a "drain" mode where unavailable
// and terminating pods are included in the list of returned pods and used to direct
// certain traffic (e.g., traffic using persistence) to terminating/unavailable pods.
func (haproxy *HAProxyController) DrainSupport() bool {
	return haproxy.currentConfig.Cfg.DrainSupport
}

// OnUpdate regenerate the configuration file of the backend
func (haproxy *HAProxyController) OnUpdate(cfg ingress.Configuration) error {
	updatedConfig := newControllerConfig(&cfg, haproxy)

	reloadRequired := reconfigureBackends(haproxy.currentConfig, updatedConfig)
	haproxy.currentConfig = updatedConfig

	data, err := haproxy.template.execute(updatedConfig)
	if err != nil {
		return err
	}

	configFile, err := haproxy.rewriteConfigFiles(data)
	if err != nil {
		return err
	}

	if !reloadRequired {
		glog.Infoln("HAProxy updated through socket, reload not required")
		return nil
	}

	reloadCmd := exec.Command(haproxy.command, *haproxy.reloadStrategy, configFile)
	out, err := reloadCmd.CombinedOutput()
	if len(out) > 0 {
		glog.Infof("HAProxy[pid=%v] output:\n%v", reloadCmd.Process.Pid, string(out))
	}
	return err
}

// RewriteConfigFiles safely replaces configuration files with new contents after validation
func (haproxy *HAProxyController) rewriteConfigFiles(data []byte) (string, error) {
	// Include timestamp in config file name to aid troubleshooting. When using a single, ever-changing config file it
	// was difficult to know what config was loaded by any given haproxy process
	timestamp := time.Now().Format("-20060102-150405.000")
	if *haproxy.maxOldConfigFiles <= 0 || *haproxy.reloadStrategy == "multibinder" {
		// multibinder currently limited to fixed config file path
		timestamp = ""
	}
	configFile := haproxy.configDir + "/" + haproxy.configFilePrefix + timestamp + haproxy.configFileSuffix

	if *haproxy.reloadStrategy == "multibinder" {
		erbFile := configFile + ".erb"
		// Write to ERB template file
		if err := ioutil.WriteFile(erbFile, data, 644); err != nil {
			glog.Warningln("Error writing rendered template to file")
			return "", err
		}

		// Generate configFile contents by processing ERB template (also validates haproxy config)
		if err := multibinderERBOnly(erbFile); err != nil {
			return "", err
		}
	} else {
		// Write directly to configFile
		if err := ioutil.WriteFile(configFile, data, 644); err != nil {
			glog.Warningln("Error writing rendered template to file")
			return "", err
		}

		// Validate haproxy config
		if err := checkValidity(configFile); err != nil {
			return "", err
		}
	}

	if *haproxy.maxOldConfigFiles > 0 {
		if err := haproxy.removeOldConfigFiles(); err != nil {
			glog.Warningf("Problem removing old config files, but continuing in case it was a fluke. err=%v", err)
		}
	}

	return configFile, nil
}

func (haproxy *HAProxyController) removeOldConfigFiles() error {
	files, err := ioutil.ReadDir(haproxy.configDir)
	if err != nil {
		return err
	}

	// Sort with most recently modified first
	sort.Slice(files, func(i,j int) bool{
		return files[i].ModTime().After(files[j].ModTime())
	})

	matchesFound := 0
	for _, f := range files {
		if !f.IsDir() && strings.HasPrefix(f.Name(), haproxy.configFilePrefix) && strings.HasSuffix(f.Name(), haproxy.configFileSuffix) {
			matchesFound = matchesFound + 1
			if matchesFound > *haproxy.maxOldConfigFiles {
				filePath := haproxy.configDir + "/" + f.Name()
				glog.Infof("Removing old config file (%v). maxOldConfigFiles=%v", filePath, *haproxy.maxOldConfigFiles)
				if err := os.Remove(filePath); err != nil {
					return err
				}
			}
		}
	}
	return nil
}

// multibinderERBOnly generates a config file from ERB template by invoking multibinder-haproxy-erb
func multibinderERBOnly(configFile string) error {
	out, err := exec.Command("multibinder-haproxy-erb", "/usr/local/sbin/haproxy", "-f", configFile, "-c", "-q").CombinedOutput()
	if err != nil {
		glog.Warningf("Error validating config file:\n%v", string(out))
		return err
	}
	return nil
}

// checkValidity runs a HAProxy configuration validity check on a file
func checkValidity(configFile string) error {
	out, err := exec.Command("haproxy", "-c", "-f", configFile).CombinedOutput()
	if err != nil {
		glog.Warningf("Error validating config file:\n%v", string(out))
		return err
	}
	return nil
}
<commit_msg>Fix nil pointer de-reference on first update.<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 controller

import (
	"github.com/golang/glog"
	"github.com/jcmoraisjr/haproxy-ingress/pkg/common/ingress"
	"github.com/jcmoraisjr/haproxy-ingress/pkg/common/ingress/controller"
	"github.com/jcmoraisjr/haproxy-ingress/pkg/common/ingress/defaults"
	"github.com/jcmoraisjr/haproxy-ingress/pkg/types"
	"github.com/jcmoraisjr/haproxy-ingress/pkg/version"
	"github.com/spf13/pflag"
	"io/ioutil"
	api "k8s.io/api/core/v1"
	extensions "k8s.io/api/extensions/v1beta1"
	"net/http"
	"os"
	"os/exec"
	"strings"
	"time"
	"sort"
)

// HAProxyController has internal data of a HAProxyController instance
type HAProxyController struct {
	controller     *controller.GenericController
	configMap      *api.ConfigMap
	storeLister    *ingress.StoreLister
	command        string
	reloadStrategy *string
	configDir     string
	configFilePrefix     string
	configFileSuffix     string
	maxOldConfigFiles     *int
	template       *template
	currentConfig  *types.ControllerConfig
}

// NewHAProxyController constructor
func NewHAProxyController() *HAProxyController {
	return &HAProxyController{}
}

// Info provides controller name and repository infos
func (haproxy *HAProxyController) Info() *ingress.BackendInfo {
	return &ingress.BackendInfo{
		Name:       "HAProxy",
		Release:    version.RELEASE,
		Build:      version.COMMIT,
		Repository: version.REPO,
	}
}

// Start starts the controller
func (haproxy *HAProxyController) Start() {
	haproxy.controller = controller.NewIngressController(haproxy)
	haproxy.controller.Start()
}

// Stop shutdown the controller process
func (haproxy *HAProxyController) Stop() error {
	err := haproxy.controller.Stop()
	return err
}

// Name provides the complete name of the controller
func (haproxy *HAProxyController) Name() string {
	return "HAProxy Ingress Controller"
}

// DefaultIngressClass returns the ingress class name
func (haproxy *HAProxyController) DefaultIngressClass() string {
	return "haproxy"
}

// Check health check implementation
func (haproxy *HAProxyController) Check(_ *http.Request) error {
	return nil
}

// SetListers give access to the store listers
func (haproxy *HAProxyController) SetListers(lister *ingress.StoreLister) {
	haproxy.storeLister = lister
}

// UpdateIngressStatus custom callback used to update the status in an Ingress rule
// If the function returns nil the standard functions will be executed.
func (haproxy *HAProxyController) UpdateIngressStatus(*extensions.Ingress) []api.LoadBalancerIngress {
	return nil
}

// ConfigureFlags allow to configure more flags before the parsing of
// command line arguments
func (haproxy *HAProxyController) ConfigureFlags(flags *pflag.FlagSet) {
	haproxy.reloadStrategy = flags.String("reload-strategy", "native",
		`Name of the reload strategy. Options are: native (default), reusesocket or multibinder`)
	haproxy.maxOldConfigFiles = flags.Int("max-old-config-files", 0,
		`Maximum old haproxy timestamped config files to allow before being cleaned up. A value <= 0 indicates a single non-timestamped config file will be used`)
	ingressClass := flags.Lookup("ingress-class")
	if ingressClass != nil {
		ingressClass.Value.Set("haproxy")
		ingressClass.DefValue = "haproxy"
	}
}

// OverrideFlags allows controller to override command line parameter flags
func (haproxy *HAProxyController) OverrideFlags(flags *pflag.FlagSet) {
	haproxy.configDir = "/etc/haproxy"
	haproxy.configFilePrefix = "haproxy"
	haproxy.configFileSuffix = ".cfg"

	if !(*haproxy.reloadStrategy == "native" || *haproxy.reloadStrategy == "reusesocket" || *haproxy.reloadStrategy == "multibinder") {
		glog.Fatalf("Unsupported reload strategy: %v", *haproxy.reloadStrategy)
	}

	if *haproxy.reloadStrategy == "multibinder" {
		haproxy.template = newTemplate("haproxy.cfg.erb.tmpl", "/etc/haproxy/haproxy.cfg.erb.tmpl")
	} else {
		haproxy.template = newTemplate("haproxy.tmpl", "/etc/haproxy/template/haproxy.tmpl")
	}
	haproxy.command = "/haproxy-reload.sh"
}

// SetConfig receives the ConfigMap the user has configured
func (haproxy *HAProxyController) SetConfig(configMap *api.ConfigMap) {
	haproxy.configMap = configMap
}

// BackendDefaults defines default values to the ingress core
func (haproxy *HAProxyController) BackendDefaults() defaults.Backend {
	return newHAProxyConfig(haproxy).Backend
}

// DefaultEndpoint returns the Endpoint to use as default when the
// referenced service does not exists
func (haproxy *HAProxyController) DefaultEndpoint() ingress.Endpoint {
	return ingress.Endpoint{
		Address: "127.0.0.1",
		Port:    "8181",
		Draining:false,
		Target:  &api.ObjectReference{},
	}
}

// Indicates whether or not this controller supports a "drain" mode where unavailable
// and terminating pods are included in the list of returned pods and used to direct
// certain traffic (e.g., traffic using persistence) to terminating/unavailable pods.
func (haproxy *HAProxyController) DrainSupport() (drainSupport bool) {
	if haproxy.currentConfig != nil {
		drainSupport = haproxy.currentConfig.Cfg.DrainSupport
	}
	return
}

// OnUpdate regenerate the configuration file of the backend
func (haproxy *HAProxyController) OnUpdate(cfg ingress.Configuration) error {
	updatedConfig := newControllerConfig(&cfg, haproxy)

	reloadRequired := reconfigureBackends(haproxy.currentConfig, updatedConfig)
	haproxy.currentConfig = updatedConfig

	data, err := haproxy.template.execute(updatedConfig)
	if err != nil {
		return err
	}

	configFile, err := haproxy.rewriteConfigFiles(data)
	if err != nil {
		return err
	}

	if !reloadRequired {
		glog.Infoln("HAProxy updated through socket, reload not required")
		return nil
	}

	reloadCmd := exec.Command(haproxy.command, *haproxy.reloadStrategy, configFile)
	out, err := reloadCmd.CombinedOutput()
	if len(out) > 0 {
		glog.Infof("HAProxy[pid=%v] output:\n%v", reloadCmd.Process.Pid, string(out))
	}
	return err
}

// RewriteConfigFiles safely replaces configuration files with new contents after validation
func (haproxy *HAProxyController) rewriteConfigFiles(data []byte) (string, error) {
	// Include timestamp in config file name to aid troubleshooting. When using a single, ever-changing config file it
	// was difficult to know what config was loaded by any given haproxy process
	timestamp := time.Now().Format("-20060102-150405.000")
	if *haproxy.maxOldConfigFiles <= 0 || *haproxy.reloadStrategy == "multibinder" {
		// multibinder currently limited to fixed config file path
		timestamp = ""
	}
	configFile := haproxy.configDir + "/" + haproxy.configFilePrefix + timestamp + haproxy.configFileSuffix

	if *haproxy.reloadStrategy == "multibinder" {
		erbFile := configFile + ".erb"
		// Write to ERB template file
		if err := ioutil.WriteFile(erbFile, data, 644); err != nil {
			glog.Warningln("Error writing rendered template to file")
			return "", err
		}

		// Generate configFile contents by processing ERB template (also validates haproxy config)
		if err := multibinderERBOnly(erbFile); err != nil {
			return "", err
		}
	} else {
		// Write directly to configFile
		if err := ioutil.WriteFile(configFile, data, 644); err != nil {
			glog.Warningln("Error writing rendered template to file")
			return "", err
		}

		// Validate haproxy config
		if err := checkValidity(configFile); err != nil {
			return "", err
		}
	}

	if *haproxy.maxOldConfigFiles > 0 {
		if err := haproxy.removeOldConfigFiles(); err != nil {
			glog.Warningf("Problem removing old config files, but continuing in case it was a fluke. err=%v", err)
		}
	}

	return configFile, nil
}

func (haproxy *HAProxyController) removeOldConfigFiles() error {
	files, err := ioutil.ReadDir(haproxy.configDir)
	if err != nil {
		return err
	}

	// Sort with most recently modified first
	sort.Slice(files, func(i,j int) bool{
		return files[i].ModTime().After(files[j].ModTime())
	})

	matchesFound := 0
	for _, f := range files {
		if !f.IsDir() && strings.HasPrefix(f.Name(), haproxy.configFilePrefix) && strings.HasSuffix(f.Name(), haproxy.configFileSuffix) {
			matchesFound = matchesFound + 1
			if matchesFound > *haproxy.maxOldConfigFiles {
				filePath := haproxy.configDir + "/" + f.Name()
				glog.Infof("Removing old config file (%v). maxOldConfigFiles=%v", filePath, *haproxy.maxOldConfigFiles)
				if err := os.Remove(filePath); err != nil {
					return err
				}
			}
		}
	}
	return nil
}

// multibinderERBOnly generates a config file from ERB template by invoking multibinder-haproxy-erb
func multibinderERBOnly(configFile string) error {
	out, err := exec.Command("multibinder-haproxy-erb", "/usr/local/sbin/haproxy", "-f", configFile, "-c", "-q").CombinedOutput()
	if err != nil {
		glog.Warningf("Error validating config file:\n%v", string(out))
		return err
	}
	return nil
}

// checkValidity runs a HAProxy configuration validity check on a file
func checkValidity(configFile string) error {
	out, err := exec.Command("haproxy", "-c", "-f", configFile).CombinedOutput()
	if err != nil {
		glog.Warningf("Error validating config file:\n%v", string(out))
		return err
	}
	return nil
}
<|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 master

import (
	"encoding/json"
	"fmt"
	"time"

	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/apimachinery/pkg/util/wait"
	genericapiserver "k8s.io/apiserver/pkg/server"
	"k8s.io/kubernetes/pkg/api"
	coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
)

type ClientCARegistrationHook struct {
	ClientCA []byte

	RequestHeaderUsernameHeaders     []string
	RequestHeaderGroupHeaders        []string
	RequestHeaderExtraHeaderPrefixes []string
	RequestHeaderCA                  []byte
	RequestHeaderAllowedNames        []string
}

func (h ClientCARegistrationHook) PostStartHook(hookContext genericapiserver.PostStartHookContext) error {
	// no work to do
	if len(h.ClientCA) == 0 && len(h.RequestHeaderCA) == 0 {
		return nil
	}

	// intializing CAs is important so that aggregated API servers can come up with "normal" config.
	// We've seen lagging etcd before, so we want to retry this a few times before we decide to crashloop
	// the API server on it.
	err := wait.Poll(1*time.Second, 30*time.Second, func() (done bool, err error) {
		// retry building the config since sometimes the server can be in an inbetween state which caused
		// some kind of auto detection failure as I recall from other post start hooks.
		// TODO see if this is still true and fix the RBAC one too if it isn't.
		client, err := coreclient.NewForConfig(hookContext.LoopbackClientConfig)
		if err != nil {
			utilruntime.HandleError(err)
			return false, nil
		}

		return h.tryToWriteClientCAs(client)
	})

	// if we're never able to make it through intialization, kill the API server
	if err != nil {
		return fmt.Errorf("unable to initialize client CA configmap: %v", err)
	}

	return nil

}

// tryToWriteClientCAs is here for unit testing with a fake client.  This is a wait.ConditionFunc so the bool
// indicates if the condition was met.  True when its finished, false when it should retry.
func (h ClientCARegistrationHook) tryToWriteClientCAs(client coreclient.CoreInterface) (bool, error) {
	if _, err := client.Namespaces().Create(&api.Namespace{ObjectMeta: metav1.ObjectMeta{Name: metav1.NamespaceSystem}}); err != nil && !apierrors.IsAlreadyExists(err) {
		utilruntime.HandleError(err)
		return false, nil
	}

	data := map[string]string{}
	if len(h.ClientCA) > 0 {
		data["client-ca-file"] = string(h.ClientCA)
	}

	if len(h.RequestHeaderCA) > 0 {
		var err error

		// encoding errors aren't going to get better, so just fail on them.
		data["requestheader-username-headers"], err = jsonSerializeStringSlice(h.RequestHeaderUsernameHeaders)
		if err != nil {
			return false, err
		}
		data["requestheader-group-headers"], err = jsonSerializeStringSlice(h.RequestHeaderGroupHeaders)
		if err != nil {
			return false, err
		}
		data["requestheader-extra-headers-prefix"], err = jsonSerializeStringSlice(h.RequestHeaderExtraHeaderPrefixes)
		if err != nil {
			return false, err
		}
		data["requestheader-client-ca-file"] = string(h.RequestHeaderCA)
		data["requestheader-allowed-names"], err = jsonSerializeStringSlice(h.RequestHeaderAllowedNames)
		if err != nil {
			return false, err
		}
	}

	// write errors may work next time if we retry, so queue for retry
	if err := writeConfigMap(client, "extension-apiserver-authentication", data); err != nil {
		utilruntime.HandleError(err)
		return false, nil
	}

	return true, nil
}

func jsonSerializeStringSlice(in []string) (string, error) {
	out, err := json.Marshal(in)
	if err != nil {
		return "", err
	}
	return string(out), err
}

func writeConfigMap(client coreclient.ConfigMapsGetter, name string, data map[string]string) error {
	existing, err := client.ConfigMaps(metav1.NamespaceSystem).Get(name, metav1.GetOptions{})
	if apierrors.IsNotFound(err) {
		_, err := client.ConfigMaps(metav1.NamespaceSystem).Create(&api.ConfigMap{
			ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: name},
			Data:       data,
		})
		return err
	}
	if err != nil {
		return err
	}

	existing.Data = data
	_, err = client.ConfigMaps(metav1.NamespaceSystem).Update(existing)
	return err
}
<commit_msg>fix the typo of intializing<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 master

import (
	"encoding/json"
	"fmt"
	"time"

	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/apimachinery/pkg/util/wait"
	genericapiserver "k8s.io/apiserver/pkg/server"
	"k8s.io/kubernetes/pkg/api"
	coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
)

type ClientCARegistrationHook struct {
	ClientCA []byte

	RequestHeaderUsernameHeaders     []string
	RequestHeaderGroupHeaders        []string
	RequestHeaderExtraHeaderPrefixes []string
	RequestHeaderCA                  []byte
	RequestHeaderAllowedNames        []string
}

func (h ClientCARegistrationHook) PostStartHook(hookContext genericapiserver.PostStartHookContext) error {
	// no work to do
	if len(h.ClientCA) == 0 && len(h.RequestHeaderCA) == 0 {
		return nil
	}

	// initializing CAs is important so that aggregated API servers can come up with "normal" config.
	// We've seen lagging etcd before, so we want to retry this a few times before we decide to crashloop
	// the API server on it.
	err := wait.Poll(1*time.Second, 30*time.Second, func() (done bool, err error) {
		// retry building the config since sometimes the server can be in an inbetween state which caused
		// some kind of auto detection failure as I recall from other post start hooks.
		// TODO see if this is still true and fix the RBAC one too if it isn't.
		client, err := coreclient.NewForConfig(hookContext.LoopbackClientConfig)
		if err != nil {
			utilruntime.HandleError(err)
			return false, nil
		}

		return h.tryToWriteClientCAs(client)
	})

	// if we're never able to make it through initialization, kill the API server
	if err != nil {
		return fmt.Errorf("unable to initialize client CA configmap: %v", err)
	}

	return nil

}

// tryToWriteClientCAs is here for unit testing with a fake client.  This is a wait.ConditionFunc so the bool
// indicates if the condition was met.  True when its finished, false when it should retry.
func (h ClientCARegistrationHook) tryToWriteClientCAs(client coreclient.CoreInterface) (bool, error) {
	if _, err := client.Namespaces().Create(&api.Namespace{ObjectMeta: metav1.ObjectMeta{Name: metav1.NamespaceSystem}}); err != nil && !apierrors.IsAlreadyExists(err) {
		utilruntime.HandleError(err)
		return false, nil
	}

	data := map[string]string{}
	if len(h.ClientCA) > 0 {
		data["client-ca-file"] = string(h.ClientCA)
	}

	if len(h.RequestHeaderCA) > 0 {
		var err error

		// encoding errors aren't going to get better, so just fail on them.
		data["requestheader-username-headers"], err = jsonSerializeStringSlice(h.RequestHeaderUsernameHeaders)
		if err != nil {
			return false, err
		}
		data["requestheader-group-headers"], err = jsonSerializeStringSlice(h.RequestHeaderGroupHeaders)
		if err != nil {
			return false, err
		}
		data["requestheader-extra-headers-prefix"], err = jsonSerializeStringSlice(h.RequestHeaderExtraHeaderPrefixes)
		if err != nil {
			return false, err
		}
		data["requestheader-client-ca-file"] = string(h.RequestHeaderCA)
		data["requestheader-allowed-names"], err = jsonSerializeStringSlice(h.RequestHeaderAllowedNames)
		if err != nil {
			return false, err
		}
	}

	// write errors may work next time if we retry, so queue for retry
	if err := writeConfigMap(client, "extension-apiserver-authentication", data); err != nil {
		utilruntime.HandleError(err)
		return false, nil
	}

	return true, nil
}

func jsonSerializeStringSlice(in []string) (string, error) {
	out, err := json.Marshal(in)
	if err != nil {
		return "", err
	}
	return string(out), err
}

func writeConfigMap(client coreclient.ConfigMapsGetter, name string, data map[string]string) error {
	existing, err := client.ConfigMaps(metav1.NamespaceSystem).Get(name, metav1.GetOptions{})
	if apierrors.IsNotFound(err) {
		_, err := client.ConfigMaps(metav1.NamespaceSystem).Create(&api.ConfigMap{
			ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: name},
			Data:       data,
		})
		return err
	}
	if err != nil {
		return err
	}

	existing.Data = data
	_, err = client.ConfigMaps(metav1.NamespaceSystem).Update(existing)
	return err
}
<|endoftext|>


<commit_before>/*
Copyright The Helm 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 installer // import "helm.sh/helm/v3/pkg/plugin/installer"

import (
	"path/filepath"

	"helm.sh/helm/v3/pkg/helmpath"
)

type base struct {
	// Source is the reference to a plugin
	Source string
}

func newBase(source string) base {
	return base{source}
}

// Path is where the plugin will be installed.
func (b *base) Path() string {
	if b.Source == "" {
		return ""
	}
	return helmpath.DataPath("plugins", filepath.Base(b.Source))
}
<commit_msg>fix HELM PLUGINS behavior another_way<commit_after>/*
Copyright The Helm 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 installer // import "helm.sh/helm/v3/pkg/plugin/installer"

import (
	"path/filepath"

	"helm.sh/helm/v3/pkg/cli"
)

type base struct {
	// Source is the reference to a plugin
	Source string
	// PluginsDirectory is the directory where plugins are installed
	PluginsDirectory string
}

func newBase(source string) base {
	settings := cli.New()
	return base{
		Source:           source,
		PluginsDirectory: settings.PluginsDirectory,
	}
}

// Path is where the plugin will be installed.
func (b *base) Path() string {
	if b.Source == "" {
		return ""
	}
	return filepath.Join(b.PluginsDirectory, filepath.Base(b.Source))
}
<|endoftext|>