<commit_before>package cmd

import (
	"bufio"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"unicode"
	"unicode/utf8"

	"github.com/PuerkitoBio/goquery"
	"github.com/fatih/color"
	"github.com/spf13/cobra"
	"golang.org/x/text/encoding/japanese"
	"golang.org/x/text/transform"
)

var errColor func(string, ...interface{}) string = color.HiYellowString
var countColor func(string, ...interface{}) string = color.HiYellowString

func newRootCmd() *cobra.Command {
	var f int

	cmd := &cobra.Command{
		Use:           "kuroneko [flags] 伝票番号",
		Short:         "ヤマト運輸のステータス取得",
		SilenceErrors: true,
		SilenceUsage:  true,

		Args: func(cmd *cobra.Command, args []string) error {
			if len(args) > 1 {
				count := strconv.Itoa(len(args))
				return fmt.Errorf("accepts at most 1 arg(s), received %s", errColor(count))
			}

			if len(args) == 0 {
				return fmt.Errorf("%s", errColor("伝票番号を入力してください"))
			}

			return nil
		},

		PreRunE: func(cmd *cobra.Command, args []string) error {
			flagCount := cmd.Flags().NFlag()
			if flagCount > 1 {
				count := strconv.Itoa(flagCount)
				return fmt.Errorf("accepte at most 1 flag(s), received %s", errColor(count))
			}

			if f < 1 || f > 10 {
				return fmt.Errorf("%s", errColor("連番で取得できるのは 1~10件 までです"))
			}

			return nil
		},

		RunE: func(cmd *cobra.Command, args []string) error {
			trackingNumber := args[0]
			flagCount := cmd.Flags().NFlag()
			if flagCount == 0 {
				return TrackShipmentsOne(trackingNumber, cmd.OutOrStdout())
			}

			return TrackShipmentsMultiple(trackingNumber, f, cmd.OutOrStdout())
		},
	}

	cmd.Flags().IntVarP(&f, "serial", "s", 1, "連番取得(10件まで)")
	cmd.SetOut(color.Output)
	cmd.SetErr(color.Error)

	return cmd
}

func Execute() {
	cmd := newRootCmd()
	if err := cmd.Execute(); err != nil {
		w := cmd.ErrOrStderr()
		fmt.Fprintf(w, "Error: %+v\n", err)
		os.Exit(1)
	}
}

func init() {}

func makeSpace(count int) string {
	// 注:全角スペース
	s := "　"
	return strings.Repeat(s, count)
}

var TrackShipmentsOne = func(s string, w io.Writer) error {
	values := url.Values{}
	values.Add("number00", "1")
	values.Add("number01", s)

	contactUrl := "http://toi.kuronekoyamato.co.jp/cgi-bin/tneko"
	resp, err := http.PostForm(contactUrl, values)
	if err != nil {
		return err
	}

	defer resp.Body.Close()

	utfBody := transform.NewReader(bufio.NewReader(resp.Body), japanese.ShiftJIS.NewDecoder())

	doc, err := goquery.NewDocumentFromReader(utfBody)
	if err != nil {
		return err
	}

	doc.Find(".saisin td").Each(func(_ int, args *goquery.Selection) {
		if args.HasClass("bold") || args.HasClass("font14") {
			text := args.Text()
			fmt.Fprintf(w, " %s\n", text)
		}
	})

	fmt.Fprintf(w, "\n")

	doc.Find(".meisai tr").Each(func(i int, args *goquery.Selection) {
		if i != 0 {
			information := args.Find("td").Map(func(_ int, s *goquery.Selection) string {
				text := s.Text()
				return text
			})
			detailInfo := information[1:6]
			statusLength := utf8.RuneCountInString(detailInfo[0])
			whitespace := 15 - statusLength
			space := makeSpace(whitespace)
			status := detailInfo[0] + space
			branchLength := utf8.RuneCountInString(detailInfo[3])
			whitespace = 20 - branchLength
			space = makeSpace(whitespace)
			branch := detailInfo[3] + space
			date, times, code := detailInfo[1], detailInfo[2], detailInfo[4]
			fmt.Fprintf(w, " %s| %s | %s | %s| %s |\n", status, date, times, branch, code)
		}
	})

	underLine := strings.Repeat("-", 99)
	fmt.Fprintf(w, "%s\n", underLine)

	return nil

}

var TrackShipmentsMultiple = func(s string, c int, w io.Writer) error {
	trackingNumber := removeHyphen(s)
	if !isInt(trackingNumber) {
		return fmt.Errorf("%s", errColor("不正な数値です"))
	}

	if !is12or11Digits(trackingNumber) {
		return fmt.Errorf("%s", errColor("12 or 11桁の伝票番号を入力してください"))
	}

	if !isCorrectNumber(trackingNumber) {
		return fmt.Errorf("%s", errColor("伝票番号に誤りがあります"))
	}

	ch := sevenCheckCalculate(trackingNumber[:len(trackingNumber)-1])
	values := url.Values{}
	values.Add("number00", "1")

	var i int
	for i = 0; i < c; i++ {
		querykey := fmt.Sprintf("number%02d", i+1)
		values.Add(querykey, <-ch)
	}

	contactUrl := "http://toi.kuronekoyamato.co.jp/cgi-bin/tneko"
	resp, err := http.PostForm(contactUrl, values)
	if err != nil {
		return err
	}

	defer resp.Body.Close()

	utfBody := transform.NewReader(bufio.NewReader(resp.Body), japanese.ShiftJIS.NewDecoder())

	doc, err := goquery.NewDocumentFromReader(utfBody)
	if err != nil {
		return err
	}

	doc.Find("center").Each(func(_ int, s *goquery.Selection) {
		hasDetail := false
		s.Find(".saisin td").Each(func(_ int, args *goquery.Selection) {
			if args.HasClass("number") {
				hasDetail = true
				subject := args.Text()
				fmt.Fprintf(w, " %s\n", countColor(subject))
			}

			if args.HasClass("bold") || args.HasClass("font14") {
				text := args.Text()
				fmt.Fprintf(w, " %s\n", text)
			}
		})

		if hasDetail {
			fmt.Fprintf(w, "\n")
		}

		s.Find(".meisai tr").Each(func(i int, args *goquery.Selection) {
			if i != 0 {
				information := args.Find("td").Map(func(_ int, s *goquery.Selection) string {
					text := s.Text()
					return text
				})
				detailInfo := information[1:6]
				statusLength := utf8.RuneCountInString(detailInfo[0])
				whitespace := 15 - statusLength
				space := makeSpace(whitespace)
				status := detailInfo[0] + space
				branchLength := utf8.RuneCountInString(detailInfo[3])
				whitespace = 20 - branchLength
				space = makeSpace(whitespace)
				branch := detailInfo[3] + space
				date, times, code := detailInfo[1], detailInfo[2], detailInfo[4]
				fmt.Fprintf(w, " %s| %s | %s | %s| %s |\n", status, date, times, branch, code)
			}
		})

		if hasDetail {
			underLine := strings.Repeat("-", 99)
			fmt.Fprintf(w, "%s\n", underLine)
		}
	})

	return nil
}

func removeHyphen(s string) string {
	if strings.Contains(s, "-") {
		removed := strings.Replace(s, "-", "", -1)
		return removed
	}
	return s
}

func sevenCheckCalculate(n string) <-chan string {
	ch := make(chan string)
	const coef = 7
	var format = "%012s"
	if len(n) == 10 {
		format = "%011s"
	}
	go func() {
		sign, _ := strconv.ParseInt(n, 10, 64)
		for {
			digit := sign % coef
			digitStr := strconv.FormatInt(digit, 10)
			trackingNumber := strconv.FormatInt(sign, 10) + digitStr
			zeroPaddingNumber := fmt.Sprintf(format, trackingNumber)
			ch <- zeroPaddingNumber
			sign++
		}
	}()
	return ch
}

func isCorrectNumber(s string) bool {
	const coef = 7
	lastDigits := s[len(s)-1:]
	otherDigits := s[:len(s)-1]
	sign, _ := strconv.ParseInt(otherDigits, 10, 64)
	digit := sign % coef
	return lastDigits == fmt.Sprint(digit)
}

func isInt(s string) bool {
	for _, c := range s {
		if !unicode.IsDigit(c) {
			return false
		}
	}
	return true
}

func is12or11Digits(s string) bool {
	if len(s) == 12 || len(s) == 11 {
		return true
	}
	return false
}
<commit_msg>fix display shift<commit_after>package cmd

import (
	"bufio"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"unicode"
	"unicode/utf8"

	"github.com/PuerkitoBio/goquery"
	"github.com/fatih/color"
	"github.com/spf13/cobra"
	"golang.org/x/text/encoding/japanese"
	"golang.org/x/text/transform"
)

var errColor func(string, ...interface{}) string = color.HiYellowString
var countColor func(string, ...interface{}) string = color.HiYellowString

func newRootCmd() *cobra.Command {
	var f int

	cmd := &cobra.Command{
		Use:           "kuroneko [flags] 伝票番号",
		Short:         "ヤマト運輸のステータス取得",
		SilenceErrors: true,
		SilenceUsage:  true,

		Args: func(cmd *cobra.Command, args []string) error {
			if len(args) > 1 {
				count := strconv.Itoa(len(args))
				return fmt.Errorf("accepts at most 1 arg(s), received %s", errColor(count))
			}

			if len(args) == 0 {
				return fmt.Errorf("%s", errColor("伝票番号を入力してください"))
			}

			return nil
		},

		PreRunE: func(cmd *cobra.Command, args []string) error {
			flagCount := cmd.Flags().NFlag()
			if flagCount > 1 {
				count := strconv.Itoa(flagCount)
				return fmt.Errorf("accepte at most 1 flag(s), received %s", errColor(count))
			}

			if f < 1 || f > 10 {
				return fmt.Errorf("%s", errColor("連番で取得できるのは 1~10件 までです"))
			}

			return nil
		},

		RunE: func(cmd *cobra.Command, args []string) error {
			trackingNumber := args[0]
			flagCount := cmd.Flags().NFlag()
			if flagCount == 0 {
				return TrackShipmentsOne(trackingNumber, cmd.OutOrStdout())
			}

			return TrackShipmentsMultiple(trackingNumber, f, cmd.OutOrStdout())
		},
	}

	cmd.Flags().IntVarP(&f, "serial", "s", 1, "連番取得(10件まで)")
	cmd.SetOut(color.Output)
	cmd.SetErr(color.Error)

	return cmd
}

func Execute() {
	cmd := newRootCmd()
	if err := cmd.Execute(); err != nil {
		w := cmd.ErrOrStderr()
		fmt.Fprintf(w, "Error: %+v\n", err)
		os.Exit(1)
	}
}

func init() {}

func makeSpace(count int) string {
	// 注:全角スペース
	s := "　"
	return strings.Repeat(s, count)
}

var TrackShipmentsOne = func(s string, w io.Writer) error {
	values := url.Values{}
	values.Add("number00", "1")
	values.Add("number01", s)

	contactUrl := "http://toi.kuronekoyamato.co.jp/cgi-bin/tneko"
	resp, err := http.PostForm(contactUrl, values)
	if err != nil {
		return err
	}

	defer resp.Body.Close()

	utfBody := transform.NewReader(bufio.NewReader(resp.Body), japanese.ShiftJIS.NewDecoder())

	doc, err := goquery.NewDocumentFromReader(utfBody)
	if err != nil {
		return err
	}

	doc.Find(".saisin td").Each(func(_ int, args *goquery.Selection) {
		if args.HasClass("bold") || args.HasClass("font14") {
			text := args.Text()
			fmt.Fprintf(w, " %s\n", text)
		}
	})

	fmt.Fprintf(w, "\n")

	doc.Find(".meisai tr").Each(func(i int, args *goquery.Selection) {
		if i != 0 {
			information := args.Find("td").Map(func(_ int, s *goquery.Selection) string {
				text := s.Text()
				return text
			})
			detailInfo := information[1:6]
			statusLength := utf8.RuneCountInString(detailInfo[0])
			whitespace := 15 - statusLength
			space := makeSpace(whitespace)
			status := detailInfo[0] + space
			branchLength := utf8.RuneCountInString(detailInfo[3])
			whitespace = 20 - branchLength
			space = makeSpace(whitespace)
			branch := detailInfo[3] + space
			date, times, code := detailInfo[1], detailInfo[2], detailInfo[4]
			if date == "" {
				date = "     "
			}
			if times == "" {
				times = "     "
			}
			fmt.Fprintf(w, " %s| %s | %s | %s| %s |\n", status, date, times, branch, code)
		}
	})

	underLine := strings.Repeat("-", 99)
	fmt.Fprintf(w, "%s\n", underLine)

	return nil

}

var TrackShipmentsMultiple = func(s string, c int, w io.Writer) error {
	trackingNumber := removeHyphen(s)
	if !isInt(trackingNumber) {
		return fmt.Errorf("%s", errColor("不正な数値です"))
	}

	if !is12or11Digits(trackingNumber) {
		return fmt.Errorf("%s", errColor("12 or 11桁の伝票番号を入力してください"))
	}

	if !isCorrectNumber(trackingNumber) {
		return fmt.Errorf("%s", errColor("伝票番号に誤りがあります"))
	}

	ch := sevenCheckCalculate(trackingNumber[:len(trackingNumber)-1])
	values := url.Values{}
	values.Add("number00", "1")

	var i int
	for i = 0; i < c; i++ {
		querykey := fmt.Sprintf("number%02d", i+1)
		values.Add(querykey, <-ch)
	}

	contactUrl := "http://toi.kuronekoyamato.co.jp/cgi-bin/tneko"
	resp, err := http.PostForm(contactUrl, values)
	if err != nil {
		return err
	}

	defer resp.Body.Close()

	utfBody := transform.NewReader(bufio.NewReader(resp.Body), japanese.ShiftJIS.NewDecoder())

	doc, err := goquery.NewDocumentFromReader(utfBody)
	if err != nil {
		return err
	}

	doc.Find("center").Each(func(_ int, s *goquery.Selection) {
		hasDetail := false
		s.Find(".saisin td").Each(func(_ int, args *goquery.Selection) {
			if args.HasClass("number") {
				hasDetail = true
				subject := args.Text()
				fmt.Fprintf(w, " %s\n", countColor(subject))
			}

			if args.HasClass("bold") || args.HasClass("font14") {
				text := args.Text()
				fmt.Fprintf(w, " %s\n", text)
			}
		})

		if hasDetail {
			fmt.Fprintf(w, "\n")
		}

		s.Find(".meisai tr").Each(func(i int, args *goquery.Selection) {
			if i != 0 {
				information := args.Find("td").Map(func(_ int, s *goquery.Selection) string {
					text := s.Text()
					return text
				})
				detailInfo := information[1:6]
				statusLength := utf8.RuneCountInString(detailInfo[0])
				whitespace := 15 - statusLength
				space := makeSpace(whitespace)
				status := detailInfo[0] + space
				branchLength := utf8.RuneCountInString(detailInfo[3])
				whitespace = 20 - branchLength
				space = makeSpace(whitespace)
				branch := detailInfo[3] + space
				date, times, code := detailInfo[1], detailInfo[2], detailInfo[4]
				if date == "" {
					date = "     "
				}
				if times == "" {
					times = "     "
				}
				fmt.Fprintf(w, " %s| %s | %s | %s| %s |\n", status, date, times, branch, code)
			}
		})

		if hasDetail {
			underLine := strings.Repeat("-", 99)
			fmt.Fprintf(w, "%s\n", underLine)
		}
	})

	return nil
}

func removeHyphen(s string) string {
	if strings.Contains(s, "-") {
		removed := strings.Replace(s, "-", "", -1)
		return removed
	}
	return s
}

func sevenCheckCalculate(n string) <-chan string {
	ch := make(chan string)
	const coef = 7
	var format = "%012s"
	if len(n) == 10 {
		format = "%011s"
	}
	go func() {
		sign, _ := strconv.ParseInt(n, 10, 64)
		for {
			digit := sign % coef
			digitStr := strconv.FormatInt(digit, 10)
			trackingNumber := strconv.FormatInt(sign, 10) + digitStr
			zeroPaddingNumber := fmt.Sprintf(format, trackingNumber)
			ch <- zeroPaddingNumber
			sign++
		}
	}()
	return ch
}

func isCorrectNumber(s string) bool {
	const coef = 7
	lastDigits := s[len(s)-1:]
	otherDigits := s[:len(s)-1]
	sign, _ := strconv.ParseInt(otherDigits, 10, 64)
	digit := sign % coef
	return lastDigits == fmt.Sprint(digit)
}

func isInt(s string) bool {
	for _, c := range s {
		if !unicode.IsDigit(c) {
			return false
		}
	}
	return true
}

func is12or11Digits(s string) bool {
	if len(s) == 12 || len(s) == 11 {
		return true
	}
	return false
}
<|endoftext|>


<commit_before>package cmd

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

	"github.com/spf13/cobra"
)

var testCmd = &cobra.Command{
	Use:     "test",
	Short:   "Runs the tests for your abcweb app",
	Long:    `Runs all Go tests for your abcweb app and skips your vendor directory.`,
	Example: "abcweb test -v",
	Run:     testCmdRun,
}

func init() {
	testCmd.Flags().BoolP("verbose", "v", false, "Enable verbose output")

	RootCmd.AddCommand(testCmd)

	testCmd.PreRun = func(*cobra.Command, []string) {
		cnf.ModeViper.BindPFlags(testCmd.Flags())
	}
}

func testCmdRun(cmd *cobra.Command, args []string) {
	checkDep("go")

	var exc *exec.Cmd

	exc = exec.Command("go", "list", "./...")
	exc.Dir = cnf.AppPath
	out, err := exc.CombinedOutput()
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	if cnf.ModeViper.GetBool("verbose") {
		exc = exec.Command("go", "test", "-v", "-p", "1")
	} else {
		exc = exec.Command("go", "test", "-p", "1")
	}

	rgx, err := regexp.Compile(filepath.Join(cnf.AppName, "vendor"))
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	pkgs := strings.Split(strings.TrimSpace(string(out)), "\n")
	for _, pkg := range pkgs {
		if !rgx.MatchString(pkg) {
			exc.Args = append(exc.Args, pkg)
		}
	}

	exc.Dir = cnf.AppPath
	out, err = exc.CombinedOutput()
	fmt.Print(string(out))

	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}
<commit_msg>fix abcweb test on windows<commit_after>package cmd

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

	"github.com/spf13/cobra"
)

var testCmd = &cobra.Command{
	Use:     "test",
	Short:   "Runs the tests for your abcweb app",
	Long:    `Runs all Go tests for your abcweb app and skips your vendor directory.`,
	Example: "abcweb test -v",
	Run:     testCmdRun,
}

func init() {
	testCmd.Flags().BoolP("verbose", "v", false, "Enable verbose output")

	RootCmd.AddCommand(testCmd)

	testCmd.PreRun = func(*cobra.Command, []string) {
		cnf.ModeViper.BindPFlags(testCmd.Flags())
	}
}

func testCmdRun(cmd *cobra.Command, args []string) {
	checkDep("go")

	var exc *exec.Cmd

	exc = exec.Command("go", "list", "./...")
	exc.Dir = cnf.AppPath
	out, err := exc.CombinedOutput()
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	if cnf.ModeViper.GetBool("verbose") {
		exc = exec.Command("go", "test", "-v", "-p", "1")
	} else {
		exc = exec.Command("go", "test", "-p", "1")
	}

	rgx, err := regexp.Compile(cnf.AppName + "/vendor")
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	pkgs := strings.Split(strings.TrimSpace(string(out)), "\n")
	for _, pkg := range pkgs {
		if !rgx.MatchString(pkg) {
			exc.Args = append(exc.Args, pkg)
		}
	}

	exc.Dir = cnf.AppPath
	out, err = exc.CombinedOutput()
	fmt.Print(string(out))

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


<commit_before>// Copyright 2017 The OPA Authors.  All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.

package cmd

import (
	"context"
	"fmt"
	"os"
	"time"

	"github.com/spf13/cobra"

	"github.com/open-policy-agent/opa/ast"
	"github.com/open-policy-agent/opa/bundle"
	"github.com/open-policy-agent/opa/compile"
	"github.com/open-policy-agent/opa/cover"
	"github.com/open-policy-agent/opa/internal/runtime"
	"github.com/open-policy-agent/opa/storage"
	"github.com/open-policy-agent/opa/storage/inmem"
	"github.com/open-policy-agent/opa/tester"
	"github.com/open-policy-agent/opa/topdown"
	"github.com/open-policy-agent/opa/topdown/lineage"
	"github.com/open-policy-agent/opa/util"
)

const (
	testPrettyOutput = "pretty"
	testJSONOutput   = "json"
)

type testCommandParams struct {
	verbose      bool
	explain      *util.EnumFlag
	errLimit     int
	outputFormat *util.EnumFlag
	coverage     bool
	threshold    float64
	timeout      time.Duration
	ignore       []string
	failureLine  bool
	bundleMode   bool
	benchmark    bool
	benchMem     bool
	runRegex     string
	count        int
	target       *util.EnumFlag
}

func newTestCommandParams() *testCommandParams {
	return &testCommandParams{
		outputFormat: util.NewEnumFlag(testPrettyOutput, []string{testPrettyOutput, testJSONOutput, benchmarkGoBenchOutput}),
		explain:      newExplainFlag([]string{explainModeFails, explainModeFull, explainModeNotes}),
		target:       util.NewEnumFlag(compile.TargetRego, []string{compile.TargetRego, compile.TargetWasm}),
	}
}

var testParams = newTestCommandParams()

var testCommand = &cobra.Command{
	Use:   "test <path> [path [...]]",
	Short: "Execute Rego test cases",
	Long: `Execute Rego test cases.

The 'test' command takes a file or directory path as input and executes all
test cases discovered in matching files. Test cases are rules whose names have the prefix "test_".

If the '--bundle' option is specified the paths will be treated as policy bundles
and loaded following standard bundle conventions. The path can be a compressed archive
file or a directory which will be treated as a bundle. Without the '--bundle' flag OPA
will recursively load ALL *.rego, *.json, and *.yaml files for evaluating the test cases.

Test cases under development may be prefixed "todo_" in order to skip their execution,
while still getting marked as skipped in the test results.

Example policy (example/authz.rego):

	package authz

	allow {
		input.path = ["users"]
		input.method = "POST"
	}

	allow {
		input.path = ["users", profile_id]
		input.method = "GET"
		profile_id = input.user_id
	}

Example test (example/authz_test.rego):

	package authz

	test_post_allowed {
		allow with input as {"path": ["users"], "method": "POST"}
	}

	test_get_denied {
		not allow with input as {"path": ["users"], "method": "GET"}
	}

	test_get_user_allowed {
		allow with input as {"path": ["users", "bob"], "method": "GET", "user_id": "bob"}
	}

	test_get_another_user_denied {
		not allow with input as {"path": ["users", "bob"], "method": "GET", "user_id": "alice"}
	}

	todo_test_user_allowed_http_client_data {
		false # Remember to test this later!
	}

Example test run:

	$ opa test ./example/

If used with the '--bench' option then tests will be benchmarked.

Example benchmark run:

	$ opa test --bench ./example/

The optional "gobench" output format conforms to the Go Benchmark Data Format.
`,
	PreRunE: func(Cmd *cobra.Command, args []string) error {
		if len(args) == 0 {
			return fmt.Errorf("specify at least one file")
		}

		// If an --explain flag was set, turn on verbose output
		if testParams.explain.IsSet() {
			testParams.verbose = true
		}

		return nil
	},

	Run: func(cmd *cobra.Command, args []string) {
		os.Exit(opaTest(args))
	},
}

func opaTest(args []string) int {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	if testParams.outputFormat.String() == benchmarkGoBenchOutput && !testParams.benchmark {
		fmt.Fprintf(os.Stderr, "cannot use output format %s without running benchmarks (--bench)\n", benchmarkGoBenchOutput)
		return 0
	}

	filter := loaderFilter{
		Ignore: testParams.ignore,
	}

	var modules map[string]*ast.Module
	var bundles map[string]*bundle.Bundle
	var store storage.Store
	var err error

	if testParams.bundleMode {
		bundles, err = tester.LoadBundles(args, filter.Apply)
		store = inmem.New()
	} else {
		modules, store, err = tester.Load(args, filter.Apply)
	}

	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	txn, err := store.NewTransaction(ctx, storage.WriteParams)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	defer store.Abort(ctx, txn)

	compiler := ast.NewCompiler().
		SetErrorLimit(testParams.errLimit).
		WithPathConflictsCheck(storage.NonEmpty(ctx, store, txn))

	info, err := runtime.Term(runtime.Params{})
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	if testParams.threshold > 0 && !testParams.coverage {
		testParams.coverage = true
	}

	var cov *cover.Cover
	var coverTracer topdown.QueryTracer

	if testParams.coverage {
		if testParams.benchmark {
			fmt.Fprintln(os.Stderr, "coverage reporting is not supported when benchmarking tests")
			return 1
		}
		cov = cover.New()
		coverTracer = cov
	}

	timeout := testParams.timeout
	if timeout == 0 { // unset
		timeout = time.Duration(5 * time.Second)
		if testParams.benchmark {
			timeout = time.Duration(30 * time.Second)
		}
	}

	runner := tester.NewRunner().
		SetCompiler(compiler).
		SetStore(store).
		EnableTracing(testParams.verbose).
		SetCoverageQueryTracer(coverTracer).
		EnableFailureLine(testParams.failureLine).
		SetRuntime(info).
		SetModules(modules).
		SetBundles(bundles).
		SetTimeout(timeout).
		Filter(testParams.runRegex).
		Target(testParams.target.String())

	var reporter tester.Reporter

	goBench := false

	if !testParams.coverage {
		switch testParams.outputFormat.String() {
		case testJSONOutput:
			reporter = tester.JSONReporter{
				Output: os.Stdout,
			}
		case benchmarkGoBenchOutput:
			goBench = true
			fallthrough
		default:
			reporter = tester.PrettyReporter{
				Verbose:                  testParams.verbose,
				FailureLine:              testParams.failureLine,
				Output:                   os.Stdout,
				BenchmarkResults:         testParams.benchmark,
				BenchMarkShowAllocations: testParams.benchMem,
				BenchMarkGoBenchFormat:   goBench,
			}
		}
	} else {
		reporter = tester.JSONCoverageReporter{
			Cover:     cov,
			Modules:   modules,
			Output:    os.Stdout,
			Threshold: testParams.threshold,
		}
	}

	for i := 0; i < testParams.count; i++ {
		exitCode := runTests(ctx, txn, runner, reporter)
		if exitCode != 0 {
			return exitCode
		}
	}

	return 0
}

func runTests(ctx context.Context, txn storage.Transaction, runner *tester.Runner, reporter tester.Reporter) int {
	var err error
	var ch chan *tester.Result
	if testParams.benchmark {
		benchOpts := tester.BenchmarkOptions{
			ReportAllocations: testParams.benchMem,
		}
		ch, err = runner.RunBenchmarks(ctx, txn, benchOpts)
	} else {
		ch, err = runner.RunTests(ctx, txn)
	}

	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	exitCode := 0
	dup := make(chan *tester.Result)

	go func() {
		defer close(dup)
		for tr := range ch {
			if !tr.Pass() {
				exitCode = 2
			}
			tr.Trace = filterTrace(testParams, tr.Trace)
			dup <- tr
		}
	}()

	if err := reporter.Report(dup); err != nil {
		fmt.Fprintln(os.Stderr, err)
		if !testParams.benchmark {
			if _, ok := err.(*cover.CoverageThresholdError); ok {
				return 2
			}
		}
		return 1
	}

	return exitCode
}

func filterTrace(params *testCommandParams, trace []*topdown.Event) []*topdown.Event {
	ops := map[topdown.Op]struct{}{}
	mode := params.explain.String()

	if mode == explainModeFull {
		// Don't bother filtering anything
		return trace
	}

	// If an explain mode was specified, filter based
	// on the mode. If no explain mode was specified,
	// default to show both notes and fail events
	showDefault := !params.explain.IsSet() && params.verbose

	if mode == explainModeNotes || showDefault {
		ops[topdown.NoteOp] = struct{}{}
	}

	if mode == explainModeFails || showDefault {
		ops[topdown.FailOp] = struct{}{}
	}

	return lineage.Filter(trace, func(event *topdown.Event) bool {
		_, relevant := ops[event.Op]
		return relevant
	})
}

func init() {
	testCommand.Flags().BoolVarP(&testParams.verbose, "verbose", "v", false, "set verbose reporting mode")
	testCommand.Flags().BoolVarP(&testParams.failureLine, "show-failure-line", "l", false, "show test failure line")
	_ = testCommand.Flags().MarkDeprecated("show-failure-line", "use -v instead")
	testCommand.Flags().DurationVar(&testParams.timeout, "timeout", 0, "set test timeout (default 5s, 30s when benchmarking)")
	testCommand.Flags().VarP(testParams.outputFormat, "format", "f", "set output format")
	testCommand.Flags().BoolVarP(&testParams.coverage, "coverage", "c", false, "report coverage (overrides debug tracing)")
	testCommand.Flags().Float64VarP(&testParams.threshold, "threshold", "", 0, "set coverage threshold and exit with non-zero status if coverage is less than threshold %")
	testCommand.Flags().BoolVar(&testParams.benchmark, "bench", false, "benchmark the unit tests")
	testCommand.Flags().StringVarP(&testParams.runRegex, "run", "r", "", "run only test cases matching the regular expression.")
	addBundleModeFlag(testCommand.Flags(), &testParams.bundleMode, false)
	addBenchmemFlag(testCommand.Flags(), &testParams.benchMem, true)
	addCountFlag(testCommand.Flags(), &testParams.count, "test")
	addMaxErrorsFlag(testCommand.Flags(), &testParams.errLimit)
	addIgnoreFlag(testCommand.Flags(), &testParams.ignore)
	setExplainFlag(testCommand.Flags(), testParams.explain)
	addTargetFlag(testCommand.Flags(), testParams.target)
	RootCommand.AddCommand(testCommand)
}
<commit_msg>opa test: change exit status when tests are skipped (#3774)<commit_after>// Copyright 2017 The OPA Authors.  All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.

package cmd

import (
	"context"
	"fmt"
	"os"
	"time"

	"github.com/spf13/cobra"

	"github.com/open-policy-agent/opa/ast"
	"github.com/open-policy-agent/opa/bundle"
	"github.com/open-policy-agent/opa/compile"
	"github.com/open-policy-agent/opa/cover"
	"github.com/open-policy-agent/opa/internal/runtime"
	"github.com/open-policy-agent/opa/storage"
	"github.com/open-policy-agent/opa/storage/inmem"
	"github.com/open-policy-agent/opa/tester"
	"github.com/open-policy-agent/opa/topdown"
	"github.com/open-policy-agent/opa/topdown/lineage"
	"github.com/open-policy-agent/opa/util"
)

const (
	testPrettyOutput = "pretty"
	testJSONOutput   = "json"
)

type testCommandParams struct {
	verbose      bool
	explain      *util.EnumFlag
	errLimit     int
	outputFormat *util.EnumFlag
	coverage     bool
	threshold    float64
	timeout      time.Duration
	ignore       []string
	failureLine  bool
	bundleMode   bool
	benchmark    bool
	benchMem     bool
	runRegex     string
	count        int
	target       *util.EnumFlag
	skipExitZero bool
}

func newTestCommandParams() *testCommandParams {
	return &testCommandParams{
		outputFormat: util.NewEnumFlag(testPrettyOutput, []string{testPrettyOutput, testJSONOutput, benchmarkGoBenchOutput}),
		explain:      newExplainFlag([]string{explainModeFails, explainModeFull, explainModeNotes}),
		target:       util.NewEnumFlag(compile.TargetRego, []string{compile.TargetRego, compile.TargetWasm}),
	}
}

var testParams = newTestCommandParams()

var testCommand = &cobra.Command{
	Use:   "test <path> [path [...]]",
	Short: "Execute Rego test cases",
	Long: `Execute Rego test cases.

The 'test' command takes a file or directory path as input and executes all
test cases discovered in matching files. Test cases are rules whose names have the prefix "test_".

If the '--bundle' option is specified the paths will be treated as policy bundles
and loaded following standard bundle conventions. The path can be a compressed archive
file or a directory which will be treated as a bundle. Without the '--bundle' flag OPA
will recursively load ALL *.rego, *.json, and *.yaml files for evaluating the test cases.

Test cases under development may be prefixed "todo_" in order to skip their execution,
while still getting marked as skipped in the test results.

Example policy (example/authz.rego):

	package authz

	allow {
		input.path = ["users"]
		input.method = "POST"
	}

	allow {
		input.path = ["users", profile_id]
		input.method = "GET"
		profile_id = input.user_id
	}

Example test (example/authz_test.rego):

	package authz

	test_post_allowed {
		allow with input as {"path": ["users"], "method": "POST"}
	}

	test_get_denied {
		not allow with input as {"path": ["users"], "method": "GET"}
	}

	test_get_user_allowed {
		allow with input as {"path": ["users", "bob"], "method": "GET", "user_id": "bob"}
	}

	test_get_another_user_denied {
		not allow with input as {"path": ["users", "bob"], "method": "GET", "user_id": "alice"}
	}

	todo_test_user_allowed_http_client_data {
		false # Remember to test this later!
	}

Example test run:

	$ opa test ./example/

If used with the '--bench' option then tests will be benchmarked.

Example benchmark run:

	$ opa test --bench ./example/

The optional "gobench" output format conforms to the Go Benchmark Data Format.
`,
	PreRunE: func(Cmd *cobra.Command, args []string) error {
		if len(args) == 0 {
			return fmt.Errorf("specify at least one file")
		}

		// If an --explain flag was set, turn on verbose output
		if testParams.explain.IsSet() {
			testParams.verbose = true
		}

		return nil
	},

	Run: func(cmd *cobra.Command, args []string) {
		os.Exit(opaTest(args))
	},
}

func opaTest(args []string) int {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	if testParams.outputFormat.String() == benchmarkGoBenchOutput && !testParams.benchmark {
		fmt.Fprintf(os.Stderr, "cannot use output format %s without running benchmarks (--bench)\n", benchmarkGoBenchOutput)
		return 0
	}

	filter := loaderFilter{
		Ignore: testParams.ignore,
	}

	var modules map[string]*ast.Module
	var bundles map[string]*bundle.Bundle
	var store storage.Store
	var err error

	if testParams.bundleMode {
		bundles, err = tester.LoadBundles(args, filter.Apply)
		store = inmem.New()
	} else {
		modules, store, err = tester.Load(args, filter.Apply)
	}

	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	txn, err := store.NewTransaction(ctx, storage.WriteParams)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	defer store.Abort(ctx, txn)

	compiler := ast.NewCompiler().
		SetErrorLimit(testParams.errLimit).
		WithPathConflictsCheck(storage.NonEmpty(ctx, store, txn))

	info, err := runtime.Term(runtime.Params{})
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	if testParams.threshold > 0 && !testParams.coverage {
		testParams.coverage = true
	}

	var cov *cover.Cover
	var coverTracer topdown.QueryTracer

	if testParams.coverage {
		if testParams.benchmark {
			fmt.Fprintln(os.Stderr, "coverage reporting is not supported when benchmarking tests")
			return 1
		}
		cov = cover.New()
		coverTracer = cov
	}

	timeout := testParams.timeout
	if timeout == 0 { // unset
		timeout = time.Duration(5 * time.Second)
		if testParams.benchmark {
			timeout = time.Duration(30 * time.Second)
		}
	}

	runner := tester.NewRunner().
		SetCompiler(compiler).
		SetStore(store).
		EnableTracing(testParams.verbose).
		SetCoverageQueryTracer(coverTracer).
		EnableFailureLine(testParams.failureLine).
		SetRuntime(info).
		SetModules(modules).
		SetBundles(bundles).
		SetTimeout(timeout).
		Filter(testParams.runRegex).
		Target(testParams.target.String())

	var reporter tester.Reporter

	goBench := false

	if !testParams.coverage {
		switch testParams.outputFormat.String() {
		case testJSONOutput:
			reporter = tester.JSONReporter{
				Output: os.Stdout,
			}
		case benchmarkGoBenchOutput:
			goBench = true
			fallthrough
		default:
			reporter = tester.PrettyReporter{
				Verbose:                  testParams.verbose,
				FailureLine:              testParams.failureLine,
				Output:                   os.Stdout,
				BenchmarkResults:         testParams.benchmark,
				BenchMarkShowAllocations: testParams.benchMem,
				BenchMarkGoBenchFormat:   goBench,
			}
		}
	} else {
		reporter = tester.JSONCoverageReporter{
			Cover:     cov,
			Modules:   modules,
			Output:    os.Stdout,
			Threshold: testParams.threshold,
		}
	}

	for i := 0; i < testParams.count; i++ {
		exitCode := runTests(ctx, txn, runner, reporter)
		if exitCode != 0 {
			return exitCode
		}
	}

	return 0
}

func runTests(ctx context.Context, txn storage.Transaction, runner *tester.Runner, reporter tester.Reporter) int {
	var err error
	var ch chan *tester.Result
	if testParams.benchmark {
		benchOpts := tester.BenchmarkOptions{
			ReportAllocations: testParams.benchMem,
		}
		ch, err = runner.RunBenchmarks(ctx, txn, benchOpts)
	} else {
		ch, err = runner.RunTests(ctx, txn)
	}

	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	exitCode := 0
	dup := make(chan *tester.Result)

	go func() {
		defer close(dup)
		for tr := range ch {
			if !tr.Pass() && !testParams.skipExitZero {
				exitCode = 2
			}
			if tr.Skip && exitCode == 0 && testParams.skipExitZero {
				// there is a skipped test, adding the flag -z exits 0 if there are no failures
				exitCode = 0
			}
			tr.Trace = filterTrace(testParams, tr.Trace)
			dup <- tr
		}
	}()

	if err := reporter.Report(dup); err != nil {
		fmt.Fprintln(os.Stderr, err)
		if !testParams.benchmark {
			if _, ok := err.(*cover.CoverageThresholdError); ok {
				return 2
			}
		}
		return 1
	}

	return exitCode
}

func filterTrace(params *testCommandParams, trace []*topdown.Event) []*topdown.Event {
	ops := map[topdown.Op]struct{}{}
	mode := params.explain.String()

	if mode == explainModeFull {
		// Don't bother filtering anything
		return trace
	}

	// If an explain mode was specified, filter based
	// on the mode. If no explain mode was specified,
	// default to show both notes and fail events
	showDefault := !params.explain.IsSet() && params.verbose

	if mode == explainModeNotes || showDefault {
		ops[topdown.NoteOp] = struct{}{}
	}

	if mode == explainModeFails || showDefault {
		ops[topdown.FailOp] = struct{}{}
	}

	return lineage.Filter(trace, func(event *topdown.Event) bool {
		_, relevant := ops[event.Op]
		return relevant
	})
}

func init() {
	testCommand.Flags().BoolVarP(&testParams.skipExitZero, "exit-zero-on-skipped", "z", false, "skipped tests return status 0")
	testCommand.Flags().BoolVarP(&testParams.verbose, "verbose", "v", false, "set verbose reporting mode")
	testCommand.Flags().BoolVarP(&testParams.failureLine, "show-failure-line", "l", false, "show test failure line")
	_ = testCommand.Flags().MarkDeprecated("show-failure-line", "use -v instead")
	testCommand.Flags().DurationVar(&testParams.timeout, "timeout", 0, "set test timeout (default 5s, 30s when benchmarking)")
	testCommand.Flags().VarP(testParams.outputFormat, "format", "f", "set output format")
	testCommand.Flags().BoolVarP(&testParams.coverage, "coverage", "c", false, "report coverage (overrides debug tracing)")
	testCommand.Flags().Float64VarP(&testParams.threshold, "threshold", "", 0, "set coverage threshold and exit with non-zero status if coverage is less than threshold %")
	testCommand.Flags().BoolVar(&testParams.benchmark, "bench", false, "benchmark the unit tests")
	testCommand.Flags().StringVarP(&testParams.runRegex, "run", "r", "", "run only test cases matching the regular expression.")
	addBundleModeFlag(testCommand.Flags(), &testParams.bundleMode, false)
	addBenchmemFlag(testCommand.Flags(), &testParams.benchMem, true)
	addCountFlag(testCommand.Flags(), &testParams.count, "test")
	addMaxErrorsFlag(testCommand.Flags(), &testParams.errLimit)
	addIgnoreFlag(testCommand.Flags(), &testParams.ignore)
	setExplainFlag(testCommand.Flags(), testParams.explain)
	addTargetFlag(testCommand.Flags(), testParams.target)
	RootCommand.AddCommand(testCommand)
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"github.com/qiniu/qshell/v2/iqshell/common/account/operations"
	"github.com/spf13/cobra"
)

var accountCmdBuilder = func() *cobra.Command {

	var accountOver bool
	var cmd = &cobra.Command{
		Use:   "account [<Id> <SecretKey> <Name>]",
		Short: "Get/Set current account's Id and SecretKey",
		Args: func(cmd *cobra.Command, args []string) error {
			if len(args) != 0 && len(args) != 3 {
				return fmt.Errorf("command account receives zero or three args, received %d\n", len(args))
			}
			return nil
		},
		Run: func(cmd *cobra.Command, args []string) {
			if len(args) == 0 {
				loadConfig()
				operations.Current()
			} else if len(args) == 3 {
				loadConfig()
				operations.Add(operations.AddInfo{
					Name:      args[2],
					AccessKey: args[0],
					SecretKey: args[1],
					Over:      accountOver,
				})
			}
		},
	}

	cmd.Flags().BoolVarP(&accountOver, "overwrite", "w", false, "overwrite account or not when account exists in local db, by default not overwrite")

	return cmd
}

var userCmdBuilder = func() *cobra.Command {
	var cmd = &cobra.Command{
		Use:   "user",
		Short: "Manage users",
	}
	return cmd
}

// 列举本地数据库记录的账户
var userLsCmdBuilder = func() *cobra.Command {
	var info = operations.ListInfo{}
	var cmd = &cobra.Command{
		Use:     "ls",
		Short:   "List all user registered",
		Example: `qshell user ls`,
		Run: func(cmd *cobra.Command, args []string) {
			loadConfig()
			operations.List(info)
		},
	}

	cmd.Flags().BoolVarP(&info.OnlyListName, "name", "n", false, "only list user names")

	return cmd
}

// 获取当前账户信息
var userCurrentCmdBuilder = func() *cobra.Command {
	var cmd = &cobra.Command{
		Use:     "current",
		Short:   "get current user info",
		Example: `qshell user current`,
		Run: func(cmd *cobra.Command, args []string) {
			loadConfig()
			operations.Current()
		},
	}
	return cmd
}

// 查询用用户是否存在本地数据库中
var userLookupCmdBuilder = func() *cobra.Command {
	var info = operations.LookUpInfo{}
	var cmd = &cobra.Command{
		Use:     "lookup <UserName>",
		Short:   "Lookup user info by user name",
		Example: `qshell user lookup <UserName>`,
		Run: func(cmd *cobra.Command, args []string) {
			if len(args) > 1 {
				info.Name = args[0]
			}
			loadConfig()
			operations.LookUp(info)
		},
	}
	return cmd
}

// 添加用户
var userAddCmdBuilder = func() *cobra.Command {

	var cmdInfo = operations.AddInfo{}
	var cmd = &cobra.Command{
		Use:   "add",
		Short: "add user info to local",
		Example: `qshell user add <AK> <SK> <UserName>
 or
 qshell user add --ak <AK> --sk <SK> --name <UserName>`,
		Run: func(cmd *cobra.Command, args []string) {
			if len(args) == 3 {
				cmdInfo.AccessKey = args[0]
				cmdInfo.SecretKey = args[1]
				cmdInfo.Name = args[2]
			}
			loadConfig()
			operations.Add(cmdInfo)
		},
	}

	cmd.Flags().StringVarP(&cmdInfo.AccessKey, "ak", "", "", "user's access key of Qiniu")
	cmd.Flags().StringVarP(&cmdInfo.SecretKey, "sk", "", "", "user's secret key of Qiniu")
	cmd.Flags().StringVarP(&cmdInfo.Name, "name", "", "", "user id of local")
	cmd.Flags().BoolVarP(&cmdInfo.Over, "overwrite", "w", false, "overwrite user or not when account exists in local db, by default not overwrite")

	return cmd
}

// 切换用户
var userChCmdBuilder = func() *cobra.Command {
	var info = operations.ChangeInfo{}
	var cmd = &cobra.Command{
		Use:     "cu [<UserName>]",
		Short:   "Change user to UserName",
		Example: `qshell user cu <UserName>`,
		Run: func(cmd *cobra.Command, args []string) {
			if len(args) > 0 {
				info.Name = args[0]
			}
			loadConfig()
			operations.Change(info)
		},
	}
	return cmd
}

// 删除本地记录的数据库
var userCleanCmdBuilder = func() *cobra.Command {
	var cmd = &cobra.Command{
		Use:     "clean",
		Short:   "clean account db",
		Long:    "Remove all users from inner dbs.",
		Example: `qshell user clean`,
		Run: func(cmd *cobra.Command, args []string) {
			loadConfig()
			operations.Clean()
		},
	}
	return cmd
}

// 删除用户
var userRmCmdBuilder = func() *cobra.Command {
	var info = operations.RemoveInfo{}
	var cmd = &cobra.Command{
		Use:     "remove <UserName>",
		Short:   "Remove user info from inner db",
		Example: `qshell user remove <UserName>`,
		Run: func(cmd *cobra.Command, args []string) {
			if len(args) > 0 {
				info.Name = args[0]
				return
			}
			loadConfig()
			operations.Remove(info)
		},
	}
	return cmd
}

func init() {
	userCmd := userCmdBuilder()
	userCmd.AddCommand(
		userAddCmdBuilder(),     // 添加用户
		userRmCmdBuilder(),      // 删除某个用户
		userCleanCmdBuilder(),   // 清除所有用户
		userChCmdBuilder(),      // 切换当前账户
		userLsCmdBuilder(),      // 列举所有用户信息
		userLookupCmdBuilder(),  // 查看某个用户的信息
		userCurrentCmdBuilder(), // 查看当前用户信息
	)

	RootCmd.AddCommand(
		accountCmdBuilder(),
		userCmd,
	)
}
<commit_msg>adjust user<commit_after>package cmd

import (
	"fmt"
	"github.com/qiniu/qshell/v2/iqshell/common/account/operations"
	"github.com/spf13/cobra"
)

var accountCmdBuilder = func() *cobra.Command {

	var accountOver bool
	var cmd = &cobra.Command{
		Use:   "account [<Id> <SecretKey> <Name>]",
		Short: "Get/Set current account's Id and SecretKey",
		Args: func(cmd *cobra.Command, args []string) error {
			if len(args) != 0 && len(args) != 3 {
				return fmt.Errorf("command account receives zero or three args, received %d\n", len(args))
			}
			return nil
		},
		Run: func(cmd *cobra.Command, args []string) {
			if len(args) == 0 {
				loadConfig()
				operations.Current()
			} else if len(args) == 3 {
				loadConfig()
				operations.Add(operations.AddInfo{
					Name:      args[2],
					AccessKey: args[0],
					SecretKey: args[1],
					Over:      accountOver,
				})
			}
		},
	}

	cmd.Flags().BoolVarP(&accountOver, "overwrite", "w", false, "overwrite account or not when account exists in local db, by default not overwrite")

	return cmd
}

var userCmdBuilder = func() *cobra.Command {
	var cmd = &cobra.Command{
		Use:   "user",
		Short: "Manage users",
	}
	return cmd
}

// 列举本地数据库记录的账户
var userLsCmdBuilder = func() *cobra.Command {
	var info = operations.ListInfo{}
	var cmd = &cobra.Command{
		Use:     "ls",
		Short:   "List all user registered",
		Example: `qshell user ls`,
		Run: func(cmd *cobra.Command, args []string) {
			loadConfig()
			operations.List(info)
		},
	}

	cmd.Flags().BoolVarP(&info.OnlyListName, "name", "n", false, "only list user names")

	return cmd
}

// 获取当前账户信息
var userCurrentCmdBuilder = func() *cobra.Command {
	var cmd = &cobra.Command{
		Use:     "current",
		Short:   "get current user info",
		Example: `qshell user current`,
		Run: func(cmd *cobra.Command, args []string) {
			loadConfig()
			operations.Current()
		},
	}
	return cmd
}

// 查询用用户是否存在本地数据库中
var userLookupCmdBuilder = func() *cobra.Command {
	var info = operations.LookUpInfo{}
	var cmd = &cobra.Command{
		Use:     "lookup <UserName>",
		Short:   "Lookup user info by user name",
		Example: `qshell user lookup <UserName>`,
		Run: func(cmd *cobra.Command, args []string) {
			if len(args) > 1 {
				info.Name = args[0]
			}
			loadConfig()
			operations.LookUp(info)
		},
	}
	return cmd
}

// 添加用户
var userAddCmdBuilder = func() *cobra.Command {

	var cmdInfo = operations.AddInfo{}
	var cmd = &cobra.Command{
		Use:   "add",
		Short: "add user info to local",
		Example: `qshell user add <AK> <SK> <UserName>
 or
 qshell user add --ak <AK> --sk <SK> --name <UserName>`,
		Run: func(cmd *cobra.Command, args []string) {
			if len(args) == 3 {
				cmdInfo.AccessKey = args[0]
				cmdInfo.SecretKey = args[1]
				cmdInfo.Name = args[2]
			}
			loadConfig()
			operations.Add(cmdInfo)
		},
	}

	cmd.Flags().StringVarP(&cmdInfo.AccessKey, "ak", "", "", "user's access key of Qiniu")
	cmd.Flags().StringVarP(&cmdInfo.SecretKey, "sk", "", "", "user's secret key of Qiniu")
	cmd.Flags().StringVarP(&cmdInfo.Name, "name", "", "", "user id of local")
	cmd.Flags().BoolVarP(&cmdInfo.Over, "overwrite", "w", false, "overwrite user or not when account exists in local db, by default not overwrite")

	return cmd
}

// 切换用户
var userChCmdBuilder = func() *cobra.Command {
	var info = operations.ChangeInfo{}
	var cmd = &cobra.Command{
		Use:     "cu [<UserName>]",
		Short:   "Change user to UserName",
		Example: `qshell user cu <UserName>`,
		Run: func(cmd *cobra.Command, args []string) {
			if len(args) > 0 {
				info.Name = args[0]
			}
			loadConfig()
			operations.Change(info)
		},
	}
	return cmd
}

// 删除本地记录的数据库
var userCleanCmdBuilder = func() *cobra.Command {
	var cmd = &cobra.Command{
		Use:     "clean",
		Short:   "clean account db",
		Long:    "Remove all users from inner dbs.",
		Example: `qshell user clean`,
		Run: func(cmd *cobra.Command, args []string) {
			loadConfig()
			operations.Clean()
		},
	}
	return cmd
}

// 删除用户
var userRmCmdBuilder = func() *cobra.Command {
	var info = operations.RemoveInfo{}
	var cmd = &cobra.Command{
		Use:     "remove <UserName>",
		Short:   "Remove user info from inner db",
		Example: `qshell user remove <UserName>`,
		Run: func(cmd *cobra.Command, args []string) {
			if len(args) > 0 {
				info.Name = args[0]
			}
			loadConfig()
			operations.Remove(info)
		},
	}
	return cmd
}

func init() {
	userCmd := userCmdBuilder()
	userCmd.AddCommand(
		userAddCmdBuilder(),     // 添加用户
		userRmCmdBuilder(),      // 删除某个用户
		userCleanCmdBuilder(),   // 清除所有用户
		userChCmdBuilder(),      // 切换当前账户
		userLsCmdBuilder(),      // 列举所有用户信息
		userLookupCmdBuilder(),  // 查看某个用户的信息
		userCurrentCmdBuilder(), // 查看当前用户信息
	)

	RootCmd.AddCommand(
		accountCmdBuilder(),
		userCmd,
	)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strings"
	"encoding/json"
	"os/exec"
)

type builtinNamespace struct{}

func (b builtinNamespace) filter(command string) bool {
	parts := strings.Split(command, " ")
	return parts[0] == "namespace" || parts[0] == "ns"
}

func (b builtinNamespace) run(command string) error {
	parts := strings.Split(command, " ")
	if len(parts) > 1 {
		return switchNamespace(parts[1])
	}
	return pickNamespace()
}

type KubernetesV1NamespaceList struct {
	Items []KubernetesV1Namespace `json:"items"`
}
type KubernetesV1Namespace struct {
	Metadata struct {
		Name string `json:"name"`
	} `json:"metadata"`
}

func namespaceSelector(selector func([]string) (string, error)) error {
	cmd := exec.Command("/bin/sh", "-c", kubectl("get namespaces --output=json"))
	jsonOut, err := cmd.Output()
	if err != nil {
		return err
	}

	var namespaces KubernetesV1NamespaceList
	err = json.Unmarshal(jsonOut, &namespaces)
	if err != nil {
		return err
	}

	targets := make([]string, len(namespaces.Items))
	for num, ns := range namespaces.Items {
		targets[num] = ns.Metadata.Name
	}

	response, err := selector(targets)
	if err != nil {
		return err
	}
	namespace = closestString(response, targets)
	return nil
}

func pickNamespace() error {
	return namespaceSelector(func(namespaces []string) (string, error) {
		for n, ns := range namespaces {
			key := fmt.Sprintf("%d", n)
			variables[key] = ns
			printIndexedLine(key, ns)
		}
		return prompt()
	})
}

func switchNamespace(ns string) error {
	return namespaceSelector(func(namespaces []string) (string, error) {
		return ns, nil
	})
}
<commit_msg>fix kubectl error message for context<commit_after>package main

import (
	"fmt"
	"strings"
	"encoding/json"
	"os/exec"
	"bytes"
)

type builtinNamespace struct{}

func (b builtinNamespace) filter(command string) bool {
	parts := strings.Split(command, " ")
	return parts[0] == "namespace" || parts[0] == "ns"
}

func (b builtinNamespace) run(command string) error {
	parts := strings.Split(command, " ")
	if len(parts) > 1 {
		return switchNamespace(parts[1])
	}
	return pickNamespace()
}

type KubernetesV1NamespaceList struct {
	Items []KubernetesV1Namespace `json:"items"`
}
type KubernetesV1Namespace struct {
	Metadata struct {
		Name string `json:"name"`
	} `json:"metadata"`
}

func namespaceSelector(selector func([]string) (string, error)) error {
	cmd := exec.Command("/bin/sh", "-c", kubectl("get namespaces --output=json"))
	var jsonOut bytes.Buffer
	var cmdErr bytes.Buffer
	cmd.Stdout = &jsonOut
	cmd.Stderr = &cmdErr

	err := cmd.Run()
	if err != nil {
		return fmt.Errorf("%v: %v", err, cmdErr.String())
	}

	var namespaces KubernetesV1NamespaceList
	err = json.Unmarshal(jsonOut.Bytes(), &namespaces)
	if err != nil {
		return err
	}

	targets := make([]string, len(namespaces.Items))
	for num, ns := range namespaces.Items {
		targets[num] = ns.Metadata.Name
	}

	response, err := selector(targets)
	if err != nil {
		return err
	}
	namespace = closestString(response, targets)
	return nil
}

func pickNamespace() error {
	return namespaceSelector(func(namespaces []string) (string, error) {
		for n, ns := range namespaces {
			key := fmt.Sprintf("%d", n)
			variables[key] = ns
			printIndexedLine(key, ns)
		}
		return prompt()
	})
}

func switchNamespace(ns string) error {
	return namespaceSelector(func(namespaces []string) (string, error) {
		return ns, nil
	})
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"text/tabwriter"

	"github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	"github.com/damonkelley/hostsup/hostsfile"
)

var Commands = []cli.Command{
	{
		Name:   "add",
		Usage:  "Add a hosts entry",
		Action: cmdAddEntry,
	},
	{
		Name:   "rm",
		Usage:  "Remove a hosts entry",
		Action: cmdRemoveEntry,
	},
	{
		Name:   "ls",
		Usage:  "List hosts entries",
		Action: cmdListEntry,
	},
	{
		Name:   "clean",
		Usage:  "Remove all hosts entries added by hostsup",
		Action: cmdClean,
	},
}

var log = logrus.New()

const HOSTSFILE string = "/etc/hosts"

func cmdAddEntry(c *cli.Context) {
	hostname := c.Args().Get(1)
	ip := c.Args().First()

	h, err := hosts_updater.NewHostsfile(HOSTSFILE)
	handleHostsfileError(err)

	host := hosts_updater.NewHost(hostname, ip)
	h.AddEntry(host)
}

func cmdRemoveEntry(c *cli.Context) {
	hostname := c.Args().First()

	h, err := hosts_updater.NewHostsfile(HOSTSFILE)
	handleHostsfileError(err)

	host := hosts_updater.NewHost(hostname, "")

	// TODO: Add a FindHost struct method to find an create a Host by the hostname.
	// Then use the returned host as a parameter to RemoveEntry.
	h.RemoveEntry(host)

}

func cmdListEntry(c *cli.Context) {
	h, _ := hosts_updater.NewHostsfile(HOSTSFILE, true)
	entries := h.ListEntries()

	w := tabwriter.NewWriter(os.Stdout, 5, 1, 3, ' ', 0)
	fmt.Fprintln(w, "HOSTNAME\tIP")

	for _, entry := range entries {
		fmt.Fprintf(w, "%s\t%s\n", entry.Hostname, entry.IP)
	}

	w.Flush()
}

func cmdClean(c *cli.Context) {
	h, err := hosts_updater.NewHostsfile(HOSTSFILE)
	handleHostsfileError(err)

	entries := h.Clean()

	for _, entry := range entries {
		log.Infof("Removed %s\t%s", entry.Hostname, entry.IP)
	}

	log.Info("Hosts file has been cleaned.")
}

func handleHostsfileError(err error) {
	if os.IsNotExist(err) {
		log.Fatalf("The file %s does not exists on your system.", HOSTSFILE)
	}

	if os.IsPermission(err) {
		log.Fatal("You do not have permission to edit this file. Try reissueing the command with sudo.")
	}
}
<commit_msg>Update cmdRemoveEntry to use FindEntry.<commit_after>package main

import (
	"fmt"
	"os"
	"text/tabwriter"

	"github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	"github.com/damonkelley/hostsup/hostsfile"
)

var Commands = []cli.Command{
	{
		Name:   "add",
		Usage:  "Add a hosts entry",
		Action: cmdAddEntry,
	},
	{
		Name:   "rm",
		Usage:  "Remove a hosts entry",
		Action: cmdRemoveEntry,
	},
	{
		Name:   "ls",
		Usage:  "List hosts entries",
		Action: cmdListEntry,
	},
	{
		Name:   "clean",
		Usage:  "Remove all hosts entries added by hostsup",
		Action: cmdClean,
	},
}

var log = logrus.New()

const HOSTSFILE string = "/etc/hosts"

func cmdAddEntry(c *cli.Context) {
	hostname := c.Args().Get(1)
	ip := c.Args().First()

	h, err := hostsfile.NewHostsfile(HOSTSFILE)
	handleHostsfileError(err)

	host := hostsfile.NewHost(hostname, ip)
	h.AddEntry(host)
}

func cmdRemoveEntry(c *cli.Context) {
	hostname := c.Args().First()

	h, err := hostsfile.NewHostsfile(HOSTSFILE)
	handleHostsfileError(err)

	host := hostsfile.NewHost(hostname, "")
	entry := h.FindEntry(hostname)

	if entry == nil {
		log.Fatalf("Unable to find a hosts entry with a hostname %s", hostname)
	}

	h.RemoveEntry(host)
}

func cmdListEntry(c *cli.Context) {
	h, _ := hostsfile.NewHostsfile(HOSTSFILE, true)
	entries := h.ListEntries()

	w := tabwriter.NewWriter(os.Stdout, 5, 1, 3, ' ', 0)
	fmt.Fprintln(w, "HOSTNAME\tIP")

	for _, entry := range entries {
		fmt.Fprintf(w, "%s\t%s\n", entry.Hostname, entry.IP)
	}

	w.Flush()
}

func cmdClean(c *cli.Context) {
	h, err := hostsfile.NewHostsfile(HOSTSFILE)
	handleHostsfileError(err)

	entries := h.Clean()

	for _, entry := range entries {
		log.Infof("Removed %s\t%s", entry.Hostname, entry.IP)
	}

	log.Info("Hosts file has been cleaned.")
}

func handleHostsfileError(err error) {
	if os.IsNotExist(err) {
		log.Fatalf("The file %s does not exists on your system.", HOSTSFILE)
	}

	if os.IsPermission(err) {
		log.Fatal("You do not have permission to edit this file. Try reissueing the command with sudo.")
	}
}
<|endoftext|>


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

package rest

import (
	"crypto/sha1"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"runtime"
	"runtime/pprof"
	"strconv"

	"github.com/couchbaselabs/sync_gateway/base"
	"github.com/couchbaselabs/sync_gateway/db"
)

const ServerName = "Couchbase Sync Gateway"
const VersionNumberString = "1.0"
const VersionString = ServerName + "/" + VersionNumberString

// HTTP handler for the root ("/")
func (h *handler) handleRoot() error {
	response := map[string]interface{}{
		"couchdb": "Welcome",
		"version": VersionString,
		"vendor":  db.Body{"name": ServerName, "version": VersionNumberString},
	}
	if h.privs == adminPrivs {
		response["ADMIN"] = true
	}
	h.writeJSON(response)
	return nil
}

func (h *handler) handleAllDbs() error {
	h.writeJSON(h.server.AllDatabaseNames())
	return nil
}

func (h *handler) handleCompact() error {
	revsDeleted, err := h.db.Compact()
	if err != nil {
		return err
	}
	h.writeJSON(db.Body{"revs": revsDeleted})
	return nil
}

func (h *handler) handleVacuum() error {
	attsDeleted, err := db.VacuumAttachments(h.db.Bucket)
	if err != nil {
		return err
	}
	h.writeJSON(db.Body{"atts": attsDeleted})
	return nil
}

func (h *handler) instanceStartTime() json.Number {
	return json.Number(strconv.FormatInt(h.db.StartTime.UnixNano()/1000, 10))
}

func (h *handler) handleGetDB() error {
	if h.rq.Method == "HEAD" {
		return nil
	}
	lastSeq, err := h.db.LastSequence()
	if err != nil {
		return err
	}
	response := db.Body{
		"db_name":              h.db.Name,
		"update_seq":           lastSeq,
		"committed_update_seq": lastSeq,
		"instance_start_time":  h.instanceStartTime(),
		"compact_running":      false, // TODO: Implement this
		"purge_seq":            0,     // TODO: Should track this value
		"disk_format_version":  0,     // Probably meaningless, but add for compatibility
		//"doc_count":          h.db.DocCount(), // Removed: too expensive to compute (#278)
	}
	h.writeJSON(response)
	return nil
}

func (h *handler) handleEFC() error { // Handles _ensure_full_commit.
	// no-op. CouchDB's replicator sends this, so don't barf. Status must be 201.
	h.writeJSONStatus(http.StatusCreated, db.Body{
		"ok": true,
		"instance_start_time": h.instanceStartTime(),
	})
	return nil
}

func (h *handler) handleDesign() error {
	designDocID := h.PathVar("docid")
	if designDocID == "sync_gateway" {
		// we serve this content here so that CouchDB 1.2 has something to
		// hash into the replication-id, to correspond to our filter.
		filter := "ok"
		if h.db.DatabaseContext.ChannelMapper != nil {
			hash := sha1.New()
			io.WriteString(hash, h.db.DatabaseContext.ChannelMapper.Function())
			filter = fmt.Sprint(hash.Sum(nil))
		}
		h.writeJSON(db.Body{"filters": db.Body{"bychannel": filter}})
		return nil
	} else {
		h.SetPathVar("docid", "_design/"+designDocID)
		return h.handleGetDoc()
	}
}

func (h *handler) handlePutDesign() error {
	designDocID := h.PathVar("docid")
	if designDocID == "sync_gateway" {
		return base.HTTPErrorf(http.StatusForbidden, "forbidden")
	} else {
		h.SetPathVar("docid", "_design/"+designDocID)
		if h.rq.Method == "DELETE" {
			return h.handleDeleteDoc()
		} else {
			return h.handlePutDoc()
		}
	}
}

// ADMIN API to turn Go CPU profiling on/off
func (h *handler) handleProfiling() error {
	profileName := h.PathVar("name")
	var params struct {
		File string `json:"file"`
	}
	body, err := h.readBody()
	if err != nil {
		return err
	}
	if len(body) > 0 {
		if err = json.Unmarshal(body, &params); err != nil {
			return err
		}
	}

	if params.File != "" {
		f, err := os.Create(params.File)
		if err != nil {
			return err
		}
		if profileName != "" {
			defer f.Close()
			if profile := pprof.Lookup(profileName); profile != nil {
				profile.WriteTo(f, 0)
				base.Log("Wrote %s profile to %s", profileName, params.File)
			} else {
				return base.HTTPErrorf(http.StatusNotFound, "No such profile %q", profileName)
			}
		} else {
			base.Log("Starting CPU profile to %s ...", params.File)
			pprof.StartCPUProfile(f)
		}
	} else {
		if profileName != "" {
			return base.HTTPErrorf(http.StatusBadRequest, "Missing JSON 'file' parameter")
		} else {
			base.Log("...ending CPU profile.")
			pprof.StopCPUProfile()
		}
	}
	return nil
}

// ADMIN API to dump Go heap profile
func (h *handler) handleHeapProfiling() error {
	var params struct {
		File string `json:"file"`
	}
	body, err := h.readBody()
	if err != nil {
		return err
	}
	if err = json.Unmarshal(body, &params); err != nil {
		return err
	}

	base.Log("Dumping heap profile to %s ...", params.File)
	f, err := os.Create(params.File)
	if err != nil {
		return err
	}
	pprof.WriteHeapProfile(f)
	f.Close()
	return nil
}

type stats struct {
	MemStats runtime.MemStats
}

// ADMIN API to expose runtime and other stats
func (h *handler) handleStats() error {
	st := stats{}
	runtime.ReadMemStats(&st.MemStats)

	h.writeJSON(st)
	return nil
}
<commit_msg>CBLT-179:  set Version constants to tokens (instantiated by build process)<commit_after>//  Copyright (c) 2012 Couchbase, Inc.
//  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
//  except in compliance with the License. You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//  Unless required by applicable law or agreed to in writing, software distributed under the
//  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
//  either express or implied. See the License for the specific language governing permissions
//  and limitations under the License.

package rest

import (
	"crypto/sha1"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"runtime"
	"runtime/pprof"
	"strconv"

	"github.com/couchbaselabs/sync_gateway/base"
	"github.com/couchbaselabs/sync_gateway/db"
)

const ServerName = "Couchbase Sync Gateway"
const VersionNumberString = "@PRODUCT_VERSION@"
const VersionCommitSHA    = "@COMMIT_SHA@"
const VersionString = ServerName + "/" + VersionNumberString

// HTTP handler for the root ("/")
func (h *handler) handleRoot() error {
	response := map[string]interface{}{
		"couchdb": "Welcome",
		"version": VersionString,
		"vendor":  db.Body{"name": ServerName, "version": VersionNumberString},
	}
	if h.privs == adminPrivs {
		response["ADMIN"] = true
	}
	h.writeJSON(response)
	return nil
}

func (h *handler) handleAllDbs() error {
	h.writeJSON(h.server.AllDatabaseNames())
	return nil
}

func (h *handler) handleCompact() error {
	revsDeleted, err := h.db.Compact()
	if err != nil {
		return err
	}
	h.writeJSON(db.Body{"revs": revsDeleted})
	return nil
}

func (h *handler) handleVacuum() error {
	attsDeleted, err := db.VacuumAttachments(h.db.Bucket)
	if err != nil {
		return err
	}
	h.writeJSON(db.Body{"atts": attsDeleted})
	return nil
}

func (h *handler) instanceStartTime() json.Number {
	return json.Number(strconv.FormatInt(h.db.StartTime.UnixNano()/1000, 10))
}

func (h *handler) handleGetDB() error {
	if h.rq.Method == "HEAD" {
		return nil
	}
	lastSeq, err := h.db.LastSequence()
	if err != nil {
		return err
	}
	response := db.Body{
		"db_name":              h.db.Name,
		"update_seq":           lastSeq,
		"committed_update_seq": lastSeq,
		"instance_start_time":  h.instanceStartTime(),
		"compact_running":      false, // TODO: Implement this
		"purge_seq":            0,     // TODO: Should track this value
		"disk_format_version":  0,     // Probably meaningless, but add for compatibility
		//"doc_count":          h.db.DocCount(), // Removed: too expensive to compute (#278)
	}
	h.writeJSON(response)
	return nil
}

func (h *handler) handleEFC() error { // Handles _ensure_full_commit.
	// no-op. CouchDB's replicator sends this, so don't barf. Status must be 201.
	h.writeJSONStatus(http.StatusCreated, db.Body{
		"ok": true,
		"instance_start_time": h.instanceStartTime(),
	})
	return nil
}

func (h *handler) handleDesign() error {
	designDocID := h.PathVar("docid")
	if designDocID == "sync_gateway" {
		// we serve this content here so that CouchDB 1.2 has something to
		// hash into the replication-id, to correspond to our filter.
		filter := "ok"
		if h.db.DatabaseContext.ChannelMapper != nil {
			hash := sha1.New()
			io.WriteString(hash, h.db.DatabaseContext.ChannelMapper.Function())
			filter = fmt.Sprint(hash.Sum(nil))
		}
		h.writeJSON(db.Body{"filters": db.Body{"bychannel": filter}})
		return nil
	} else {
		h.SetPathVar("docid", "_design/"+designDocID)
		return h.handleGetDoc()
	}
}

func (h *handler) handlePutDesign() error {
	designDocID := h.PathVar("docid")
	if designDocID == "sync_gateway" {
		return base.HTTPErrorf(http.StatusForbidden, "forbidden")
	} else {
		h.SetPathVar("docid", "_design/"+designDocID)
		if h.rq.Method == "DELETE" {
			return h.handleDeleteDoc()
		} else {
			return h.handlePutDoc()
		}
	}
}

// ADMIN API to turn Go CPU profiling on/off
func (h *handler) handleProfiling() error {
	profileName := h.PathVar("name")
	var params struct {
		File string `json:"file"`
	}
	body, err := h.readBody()
	if err != nil {
		return err
	}
	if len(body) > 0 {
		if err = json.Unmarshal(body, &params); err != nil {
			return err
		}
	}

	if params.File != "" {
		f, err := os.Create(params.File)
		if err != nil {
			return err
		}
		if profileName != "" {
			defer f.Close()
			if profile := pprof.Lookup(profileName); profile != nil {
				profile.WriteTo(f, 0)
				base.Log("Wrote %s profile to %s", profileName, params.File)
			} else {
				return base.HTTPErrorf(http.StatusNotFound, "No such profile %q", profileName)
			}
		} else {
			base.Log("Starting CPU profile to %s ...", params.File)
			pprof.StartCPUProfile(f)
		}
	} else {
		if profileName != "" {
			return base.HTTPErrorf(http.StatusBadRequest, "Missing JSON 'file' parameter")
		} else {
			base.Log("...ending CPU profile.")
			pprof.StopCPUProfile()
		}
	}
	return nil
}

// ADMIN API to dump Go heap profile
func (h *handler) handleHeapProfiling() error {
	var params struct {
		File string `json:"file"`
	}
	body, err := h.readBody()
	if err != nil {
		return err
	}
	if err = json.Unmarshal(body, &params); err != nil {
		return err
	}

	base.Log("Dumping heap profile to %s ...", params.File)
	f, err := os.Create(params.File)
	if err != nil {
		return err
	}
	pprof.WriteHeapProfile(f)
	f.Close()
	return nil
}

type stats struct {
	MemStats runtime.MemStats
}

// ADMIN API to expose runtime and other stats
func (h *handler) handleStats() error {
	st := stats{}
	runtime.ReadMemStats(&st.MemStats)

	h.writeJSON(st)
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2013 The Gorilla 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 handlers

import (
	"compress/flate"
	"compress/gzip"
	"io"
	"net/http"
	"strings"
)

type compressResponseWriter struct {
	io.Writer
	http.ResponseWriter
	http.Hijacker
	http.Flusher
	http.CloseNotifier
}

func (w *compressResponseWriter) WriteHeader(c int) {
	w.ResponseWriter.Header().Del("Content-Length")
	w.ResponseWriter.WriteHeader(c)
}

func (w *compressResponseWriter) Header() http.Header {
	return w.ResponseWriter.Header()
}

func (w *compressResponseWriter) Write(b []byte) (int, error) {
	h := w.ResponseWriter.Header()
	if h.Get("Content-Type") == "" {
		h.Set("Content-Type", http.DetectContentType(b))
	}
	h.Del("Content-Length")

	return w.Writer.Write(b)
}

type flusher interface {
	Flush() error
}

func (w *compressResponseWriter) Flush() {
	// Flush compressed data if compressor supports it.
	if f, ok := w.Writer.(flusher); ok {
		f.Flush()
	}
	// Flush HTTP response.
	if w.Flusher != nil {
		w.Flusher.Flush()
	}
}

// CompressHandler gzip compresses HTTP responses for clients that support it
// via the 'Accept-Encoding' header.
func CompressHandler(h http.Handler) http.Handler {
	return CompressHandlerLevel(h, gzip.DefaultCompression)
}

// CompressHandlerLevel gzip compresses HTTP responses with specified compression level
// for clients that support it via the 'Accept-Encoding' header.
//
// The compression level should be gzip.DefaultCompression, gzip.NoCompression,
// or any integer value between gzip.BestSpeed and gzip.BestCompression inclusive.
// gzip.DefaultCompression is used in case of invalid compression level.
func CompressHandlerLevel(h http.Handler, level int) http.Handler {
	if level < gzip.DefaultCompression || level > gzip.BestCompression {
		level = gzip.DefaultCompression
	}

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	L:
		for _, enc := range strings.Split(r.Header.Get("Accept-Encoding"), ",") {
			switch strings.TrimSpace(enc) {
			case "gzip":
				w.Header().Set("Content-Encoding", "gzip")
				w.Header().Add("Vary", "Accept-Encoding")

				gw, _ := gzip.NewWriterLevel(w, level)
				defer gw.Close()

				h, hok := w.(http.Hijacker)
				if !hok { /* w is not Hijacker... oh well... */
					h = nil
				}

				f, fok := w.(http.Flusher)
				if !fok {
					f = nil
				}

				cn, cnok := w.(http.CloseNotifier)
				if !cnok {
					cn = nil
				}

				w = &compressResponseWriter{
					Writer:         gw,
					ResponseWriter: w,
					Hijacker:       h,
					Flusher:        f,
					CloseNotifier:  cn,
				}

				break L
			case "deflate":
				w.Header().Set("Content-Encoding", "deflate")
				w.Header().Add("Vary", "Accept-Encoding")

				fw, _ := flate.NewWriter(w, level)
				defer fw.Close()

				h, hok := w.(http.Hijacker)
				if !hok { /* w is not Hijacker... oh well... */
					h = nil
				}

				f, fok := w.(http.Flusher)
				if !fok {
					f = nil
				}

				cn, cnok := w.(http.CloseNotifier)
				if !cnok {
					cn = nil
				}

				w = &compressResponseWriter{
					Writer:         fw,
					ResponseWriter: w,
					Hijacker:       h,
					Flusher:        f,
					CloseNotifier:  cn,
				}

				break L
			}
		}

		h.ServeHTTP(w, r)
	})
}
<commit_msg>[docs] Add note about the CompressHandler and TLS traffic (#90)<commit_after>// Copyright 2013 The Gorilla 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 handlers

import (
	"compress/flate"
	"compress/gzip"
	"io"
	"net/http"
	"strings"
)

type compressResponseWriter struct {
	io.Writer
	http.ResponseWriter
	http.Hijacker
	http.Flusher
	http.CloseNotifier
}

func (w *compressResponseWriter) WriteHeader(c int) {
	w.ResponseWriter.Header().Del("Content-Length")
	w.ResponseWriter.WriteHeader(c)
}

func (w *compressResponseWriter) Header() http.Header {
	return w.ResponseWriter.Header()
}

func (w *compressResponseWriter) Write(b []byte) (int, error) {
	h := w.ResponseWriter.Header()
	if h.Get("Content-Type") == "" {
		h.Set("Content-Type", http.DetectContentType(b))
	}
	h.Del("Content-Length")

	return w.Writer.Write(b)
}

type flusher interface {
	Flush() error
}

func (w *compressResponseWriter) Flush() {
	// Flush compressed data if compressor supports it.
	if f, ok := w.Writer.(flusher); ok {
		f.Flush()
	}
	// Flush HTTP response.
	if w.Flusher != nil {
		w.Flusher.Flush()
	}
}

// CompressHandler gzip compresses HTTP responses for clients that support it
// via the 'Accept-Encoding' header.
//
// Compressing TLS traffic may leak the page contents to an attacker if the
// page contains user input: http://security.stackexchange.com/a/102015/12208
func CompressHandler(h http.Handler) http.Handler {
	return CompressHandlerLevel(h, gzip.DefaultCompression)
}

// CompressHandlerLevel gzip compresses HTTP responses with specified compression level
// for clients that support it via the 'Accept-Encoding' header.
//
// The compression level should be gzip.DefaultCompression, gzip.NoCompression,
// or any integer value between gzip.BestSpeed and gzip.BestCompression inclusive.
// gzip.DefaultCompression is used in case of invalid compression level.
func CompressHandlerLevel(h http.Handler, level int) http.Handler {
	if level < gzip.DefaultCompression || level > gzip.BestCompression {
		level = gzip.DefaultCompression
	}

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	L:
		for _, enc := range strings.Split(r.Header.Get("Accept-Encoding"), ",") {
			switch strings.TrimSpace(enc) {
			case "gzip":
				w.Header().Set("Content-Encoding", "gzip")
				w.Header().Add("Vary", "Accept-Encoding")

				gw, _ := gzip.NewWriterLevel(w, level)
				defer gw.Close()

				h, hok := w.(http.Hijacker)
				if !hok { /* w is not Hijacker... oh well... */
					h = nil
				}

				f, fok := w.(http.Flusher)
				if !fok {
					f = nil
				}

				cn, cnok := w.(http.CloseNotifier)
				if !cnok {
					cn = nil
				}

				w = &compressResponseWriter{
					Writer:         gw,
					ResponseWriter: w,
					Hijacker:       h,
					Flusher:        f,
					CloseNotifier:  cn,
				}

				break L
			case "deflate":
				w.Header().Set("Content-Encoding", "deflate")
				w.Header().Add("Vary", "Accept-Encoding")

				fw, _ := flate.NewWriter(w, level)
				defer fw.Close()

				h, hok := w.(http.Hijacker)
				if !hok { /* w is not Hijacker... oh well... */
					h = nil
				}

				f, fok := w.(http.Flusher)
				if !fok {
					f = nil
				}

				cn, cnok := w.(http.CloseNotifier)
				if !cnok {
					cn = nil
				}

				w = &compressResponseWriter{
					Writer:         fw,
					ResponseWriter: w,
					Hijacker:       h,
					Flusher:        f,
					CloseNotifier:  cn,
				}

				break L
			}
		}

		h.ServeHTTP(w, r)
	})
}
<|endoftext|>


<commit_before>/*
Copyright 2018 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 mount

import (
	"fmt"
	"os"
	"time"

	"k8s.io/klog/v2"
)

// CleanupMountPoint unmounts the given path and deletes the remaining directory
// if successful. If extensiveMountPointCheck is true IsNotMountPoint will be
// called instead of IsLikelyNotMountPoint. IsNotMountPoint is more expensive
// but properly handles bind mounts within the same fs.
func CleanupMountPoint(mountPath string, mounter Interface, extensiveMountPointCheck bool) error {
	pathExists, pathErr := PathExists(mountPath)
	if !pathExists && pathErr == nil {
		klog.Warningf("Warning: Unmount skipped because path does not exist: %v", mountPath)
		return nil
	}
	corruptedMnt := IsCorruptedMnt(pathErr)
	if pathErr != nil && !corruptedMnt {
		return fmt.Errorf("Error checking path: %v", pathErr)
	}
	return doCleanupMountPoint(mountPath, mounter, extensiveMountPointCheck, corruptedMnt)
}

func CleanupMountWithForce(mountPath string, mounter MounterForceUnmounter, extensiveMountPointCheck bool, umountTimeout time.Duration) error {
	pathExists, pathErr := PathExists(mountPath)
	if !pathExists && pathErr == nil {
		klog.Warningf("Warning: Unmount skipped because path does not exist: %v", mountPath)
		return nil
	}
	corruptedMnt := IsCorruptedMnt(pathErr)
	if pathErr != nil && !corruptedMnt {
		return fmt.Errorf("Error checking path: %v", pathErr)
	}
	var notMnt bool
	var err error
	if !mounter.canSafelySkipMountPointCheck() && !corruptedMnt {
		notMnt, err = removePathIfNotMountPoint(mountPath, mounter, extensiveMountPointCheck)
		// if mountPath was not a mount point - we would have attempted to remove mountPath
		// and hence return errors if any.
		if err != nil || notMnt {
			return err
		}
	}

	// Unmount the mount path
	klog.V(4).Infof("%q is a mountpoint, unmounting", mountPath)
	if err := mounter.UnmountWithForce(mountPath, umountTimeout); err != nil {
		return err
	}

	if mounter.canSafelySkipMountPointCheck() {
		return removePath(mountPath)
	}

	notMnt, err = removePathIfNotMountPoint(mountPath, mounter, extensiveMountPointCheck)
	// mountPath is not a mount point we should return whatever error we saw
	if notMnt {
		return err
	}
	return fmt.Errorf("Failed to unmount path %v", mountPath)
}

// doCleanupMountPoint unmounts the given path and
// deletes the remaining directory if successful.
// if extensiveMountPointCheck is true
// IsNotMountPoint will be called instead of IsLikelyNotMountPoint.
// IsNotMountPoint is more expensive but properly handles bind mounts within the same fs.
// if corruptedMnt is true, it means that the mountPath is a corrupted mountpoint, and the mount point check
// will be skipped. The mount point check will also be skipped if the mounter supports it.
func doCleanupMountPoint(mountPath string, mounter Interface, extensiveMountPointCheck bool, corruptedMnt bool) error {
	var notMnt bool
	var err error
	if !mounter.canSafelySkipMountPointCheck() && !corruptedMnt {
		notMnt, err = removePathIfNotMountPoint(mountPath, mounter, extensiveMountPointCheck)
		// if mountPath was not a mount point - we would have attempted to remove mountPath
		// and hence return errors if any.
		if err != nil || notMnt {
			return err
		}
	}

	// Unmount the mount path
	klog.V(4).Infof("%q is a mountpoint, unmounting", mountPath)
	if err := mounter.Unmount(mountPath); err != nil {
		return err
	}

	if mounter.canSafelySkipMountPointCheck() {
		return removePath(mountPath)
	}

	notMnt, err = removePathIfNotMountPoint(mountPath, mounter, extensiveMountPointCheck)
	// mountPath is not a mount point we should return whatever error we saw
	if notMnt {
		return err
	}
	return fmt.Errorf("Failed to unmount path %v", mountPath)
}

// removePathIfNotMountPoint verifies if given mountPath is a mount point if not it attempts
// to remove the directory. Returns true and nil if directory was not a mount point and removed.
func removePathIfNotMountPoint(mountPath string, mounter Interface, extensiveMountPointCheck bool) (bool, error) {
	var notMnt bool
	var err error

	if extensiveMountPointCheck {
		notMnt, err = IsNotMountPoint(mounter, mountPath)
	} else {
		notMnt, err = mounter.IsLikelyNotMountPoint(mountPath)
	}

	if err != nil {
		if os.IsNotExist(err) {
			klog.V(4).Infof("%q does not exist", mountPath)
			return true, nil
		}
		return notMnt, err
	}

	if notMnt {
		klog.Warningf("Warning: %q is not a mountpoint, deleting", mountPath)
		return notMnt, os.Remove(mountPath)
	}
	return notMnt, nil
}

// removePath attempts to remove the directory. Returns nil if the directory was removed or does not exist.
func removePath(mountPath string) error {
	klog.V(4).Infof("Warning: deleting path %q", mountPath)
	err := os.Remove(mountPath)
	if os.IsNotExist(err) {
		klog.V(4).Infof("%q does not exist", mountPath)
		return nil
	}
	return err
}
<commit_msg>Rework for readability<commit_after>/*
Copyright 2018 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 mount

import (
	"fmt"
	"os"
	"time"

	"k8s.io/klog/v2"
)

// CleanupMountPoint unmounts the given path and deletes the remaining directory
// if successful. If extensiveMountPointCheck is true IsNotMountPoint will be
// called instead of IsLikelyNotMountPoint. IsNotMountPoint is more expensive
// but properly handles bind mounts within the same fs.
func CleanupMountPoint(mountPath string, mounter Interface, extensiveMountPointCheck bool) error {
	pathExists, pathErr := PathExists(mountPath)
	if !pathExists && pathErr == nil {
		klog.Warningf("Warning: mount cleanup skipped because path does not exist: %v", mountPath)
		return nil
	}
	corruptedMnt := IsCorruptedMnt(pathErr)
	if pathErr != nil && !corruptedMnt {
		return fmt.Errorf("Error checking path: %v", pathErr)
	}
	return doCleanupMountPoint(mountPath, mounter, extensiveMountPointCheck, corruptedMnt)
}

func CleanupMountWithForce(mountPath string, mounter MounterForceUnmounter, extensiveMountPointCheck bool, umountTimeout time.Duration) error {
	pathExists, pathErr := PathExists(mountPath)
	if !pathExists && pathErr == nil {
		klog.Warningf("Warning: mount cleanup skipped because path does not exist: %v", mountPath)
		return nil
	}
	corruptedMnt := IsCorruptedMnt(pathErr)
	if pathErr != nil && !corruptedMnt {
		return fmt.Errorf("Error checking path: %v", pathErr)
	}

	if corruptedMnt || mounter.canSafelySkipMountPointCheck() {
		klog.V(4).Infof("unmounting %q", mountPath)
		if err := mounter.UnmountWithForce(mountPath, umountTimeout); err != nil {
			return err
		}
		return removePath(mountPath)
	}

	notMnt, err := removePathIfNotMountPoint(mountPath, mounter, extensiveMountPointCheck)
	// if mountPath is not a mount point, it's just been removed or there was an error
	if err != nil || notMnt {
		return err
	}

	klog.V(4).Infof("%q is a mountpoint, unmounting", mountPath)
	if err := mounter.UnmountWithForce(mountPath, umountTimeout); err != nil {
		return err
	}

	notMnt, err = removePathIfNotMountPoint(mountPath, mounter, extensiveMountPointCheck)
	// if mountPath is not a mount point, it's either just been removed or there was an error
	if notMnt {
		return err
	}
	// mountPath is still a mount point
	return fmt.Errorf("failed to cleanup mount point %v", mountPath)
}

// doCleanupMountPoint unmounts the given path and
// deletes the remaining directory if successful.
// if extensiveMountPointCheck is true
// IsNotMountPoint will be called instead of IsLikelyNotMountPoint.
// IsNotMountPoint is more expensive but properly handles bind mounts within the same fs.
// if corruptedMnt is true, it means that the mountPath is a corrupted mountpoint, and the mount point check
// will be skipped. The mount point check will also be skipped if the mounter supports it.
func doCleanupMountPoint(mountPath string, mounter Interface, extensiveMountPointCheck bool, corruptedMnt bool) error {
	if corruptedMnt || mounter.canSafelySkipMountPointCheck() {
		klog.V(4).Infof("unmounting %q", mountPath)
		if err := mounter.Unmount(mountPath); err != nil {
			return err
		}
		return removePath(mountPath)
	}

	notMnt, err := removePathIfNotMountPoint(mountPath, mounter, extensiveMountPointCheck)
	// if mountPath is not a mount point, it's just been removed or there was an error
	if err != nil || notMnt {
		return err
	}

	klog.V(4).Infof("%q is a mountpoint, unmounting", mountPath)
	if err := mounter.Unmount(mountPath); err != nil {
		return err
	}

	notMnt, err = removePathIfNotMountPoint(mountPath, mounter, extensiveMountPointCheck)
	// if mountPath is not a mount point, it's either just been removed or there was an error
	if notMnt {
		return err
	}
	// mountPath is still a mount point
	return fmt.Errorf("failed to cleanup mount point %v", mountPath)
}

// removePathIfNotMountPoint verifies if given mountPath is a mount point if not it attempts
// to remove the directory. Returns true and nil if directory was not a mount point and removed.
func removePathIfNotMountPoint(mountPath string, mounter Interface, extensiveMountPointCheck bool) (bool, error) {
	var notMnt bool
	var err error

	if extensiveMountPointCheck {
		notMnt, err = IsNotMountPoint(mounter, mountPath)
	} else {
		notMnt, err = mounter.IsLikelyNotMountPoint(mountPath)
	}

	if err != nil {
		if os.IsNotExist(err) {
			klog.V(4).Infof("%q does not exist", mountPath)
			return true, nil
		}
		return notMnt, err
	}

	if notMnt {
		klog.Warningf("Warning: %q is not a mountpoint, deleting", mountPath)
		return notMnt, os.Remove(mountPath)
	}
	return notMnt, nil
}

// removePath attempts to remove the directory. Returns nil if the directory was removed or does not exist.
func removePath(mountPath string) error {
	klog.V(4).Infof("Warning: deleting path %q", mountPath)
	err := os.Remove(mountPath)
	if os.IsNotExist(err) {
		klog.V(4).Infof("%q does not exist", mountPath)
		return nil
	}
	return err
}
<|endoftext|>