<commit_before>/*
Copyright 2019 The Kubernetes Authors All rights reserved.

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

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

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

package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

var (
	skippedPaths   = regexp.MustCompile(`Godeps|third_party|_gopath|_output|\.git|cluster/env.sh|vendor|test/e2e/generated/bindata.go|site/themes/docsy`)
	boilerplatedir = flag.String("boilerplate-dir", ".", "Boilerplate directory for boilerplate files")
	rootdir        = flag.String("rootdir", "../../", "Root directory to examine")
	verbose        = flag.Bool("v", false, "Verbose")
)

func main() {
	flag.Parse()
	refs, err := extensionToBoilerplate(*boilerplatedir)
	if err != nil {
		log.Fatal(err)
	}
	if len(refs) == 0 {
		log.Fatal("no references in ", *boilerplatedir)
	}
	files, err := filesToCheck(*rootdir, refs)
	if err != nil {
		log.Fatal(err)
	}
	for _, file := range files {
		pass, err := filePasses(file, refs[fileExtension(file)])
		if err != nil {
			log.Println(err)
		}
		if !pass {
			path, err := filepath.Abs(file)
			if err != nil {
				log.Println(err)
			}
			fmt.Println(path)
		}
	}

}

// extensionToBoilerplate returns a map of file extension to required boilerplate text
func extensionToBoilerplate(dir string) (map[string][]byte, error) {
	refs := make(map[string][]byte)
	files, _ := filepath.Glob(dir + "/*.txt")
	for _, filename := range files {
		re := regexp.MustCompile(`\.txt`)
		extension := strings.ToLower(fileExtension(re.ReplaceAllString(filename, "")))
		data, err := ioutil.ReadFile(filename)
		if err != nil {
			return nil, err
		}
		re = regexp.MustCompile(`\r`)
		refs[extension] = re.ReplaceAll(data, nil)
	}
	if *verbose {
		dir, err := filepath.Abs(dir)
		if err != nil {
			return refs, err
		}
		fmt.Printf("Found %v boilerplates in %v for the following extensions:", len(refs), dir)
		for ext, _ := range refs {
			fmt.Printf(" %v", ext)
		}
		fmt.Println()
	}
	return refs, nil
}

// filePasses checks whether the processed file is valid. Returning false means that the file does not the proper boilerplate template.
func filePasses(filename string, expectedBoilerplate []byte) (bool, error) {
	var re *regexp.Regexp
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		return false, err
	}
	re = regexp.MustCompile(`\r`)
	data = re.ReplaceAll(data, nil)

	extension := fileExtension(filename)

	// remove build tags from the top of Go files
	if extension == "go" {
		re = regexp.MustCompile(`(?m)^(// \+build.*\n)+\n`)
		data = re.ReplaceAll(data, nil)
	}

	// remove shebang from the top of shell files
	if extension == "sh" {
		re = regexp.MustCompile(`(?m)^(#!.*\n)\n*`)
		data = re.ReplaceAll(data, nil)
	}

	// if our test file is smaller than the reference it surely fails!
	if len(data) < len(expectedBoilerplate) {
		return false, nil
	}

	data = data[:len(expectedBoilerplate)]

	// Search for "Copyright YEAR" which exists in the boilerplate, but shouldn't in the real thing
	re = regexp.MustCompile(`Copyright YEAR`)
	if re.Match(data) {
		return false, nil
	}

	// Replace all occurrences of the regex "Copyright \d{4}" with "Copyright YEAR"
	re = regexp.MustCompile(`Copyright \d{4}`)
	data = re.ReplaceAll(data, []byte(`Copyright YEAR`))

	return bytes.Equal(data, expectedBoilerplate), nil
}

/**
Function to get the file extensin or the filename if the file has no extension
*/
func fileExtension(filename string) string {
	splitted := strings.Split(filepath.Base(filename), ".")
	return strings.ToLower(splitted[len(splitted)-1])
}

// filesToCheck returns the list of the filers that will be checked for the boilerplate.
func filesToCheck(rootDir string, extensions map[string][]byte) ([]string, error) {
	var outFiles []string
	err := filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error {
		// remove current workdir from the beginig of the path in case it matches the skipped path
		cwd, _ := os.Getwd()
		// replace "\" with "\\" for windows style path
		re := regexp.MustCompile(`\\`)
		re = regexp.MustCompile(`^` + re.ReplaceAllString(cwd, `\\`))
		if !info.IsDir() && !skippedPaths.MatchString(re.ReplaceAllString(filepath.Dir(path), "")) {
			if extensions[strings.ToLower(fileExtension(path))] != nil {
				outFiles = append(outFiles, path)
			}
		}
		return nil
	})
	if err != nil {
		return nil, err
	}
	if *verbose {
		rootDir, err = filepath.Abs(rootDir)
		if err != nil {
			return outFiles, err
		}
		fmt.Printf("Found %v files to check in %v\n\n", len(outFiles), rootDir)
	}
	return outFiles, nil
}
<commit_msg>fileExtension function replaced with filepath.Ext in boilerplate.go<commit_after>/*
Copyright 2019 The Kubernetes Authors All rights reserved.

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

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

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

package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

var (
	skippedPaths   = regexp.MustCompile(`Godeps|third_party|_gopath|_output|\.git|cluster/env.sh|vendor|test/e2e/generated/bindata.go|site/themes/docsy`)
	boilerplatedir = flag.String("boilerplate-dir", ".", "Boilerplate directory for boilerplate files")
	rootdir        = flag.String("rootdir", "../../", "Root directory to examine")
	verbose        = flag.Bool("v", false, "Verbose")
)

func main() {
	flag.Parse()
	refs, err := extensionToBoilerplate(*boilerplatedir)
	if err != nil {
		log.Fatal(err)
	}
	if len(refs) == 0 {
		log.Fatal("no references in ", *boilerplatedir)
	}
	files, err := filesToCheck(*rootdir, refs)
	if err != nil {
		log.Fatal(err)
	}
	for _, file := range files {
		pass, err := filePasses(file, refs[filepath.Ext(file)])
		if err != nil {
			log.Println(err)
		}
		if !pass {
			path, err := filepath.Abs(file)
			if err != nil {
				log.Println(err)
			}
			fmt.Println(path)
		}
	}

}

// extensionToBoilerplate returns a map of file extension to required boilerplate text
func extensionToBoilerplate(dir string) (map[string][]byte, error) {
	refs := make(map[string][]byte)
	files, _ := filepath.Glob(dir + "/*.txt")
	for _, filename := range files {
		re := regexp.MustCompile(`\.txt`)
		extension := strings.ToLower(filepath.Ext(re.ReplaceAllString(filename, "")))
		data, err := ioutil.ReadFile(filename)
		if err != nil {
			return nil, err
		}
		re = regexp.MustCompile(`\r`)
		refs[extension] = re.ReplaceAll(data, nil)
	}
	if *verbose {
		dir, err := filepath.Abs(dir)
		if err != nil {
			return refs, err
		}
		fmt.Printf("Found %v boilerplates in %v for the following extensions:", len(refs), dir)
		for ext := range refs {
			fmt.Printf(" %v", ext)
		}
		fmt.Println()
	}
	return refs, nil
}

// filePasses checks whether the processed file is valid. Returning false means that the file does not the proper boilerplate template.
func filePasses(filename string, expectedBoilerplate []byte) (bool, error) {
	var re *regexp.Regexp
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		return false, err
	}
	re = regexp.MustCompile(`\r`)
	data = re.ReplaceAll(data, nil)

	extension := filepath.Ext(filename)

	// remove build tags from the top of Go files
	if extension == ".go" {
		re = regexp.MustCompile(`(?m)^(// \+build.*\n)+\n`)
		data = re.ReplaceAll(data, nil)
	}

	// remove shebang from the top of shell files
	if extension == ".sh" {
		re = regexp.MustCompile(`(?m)^(#!.*\n)\n*`)
		data = re.ReplaceAll(data, nil)
	}

	// if our test file is smaller than the reference it surely fails!
	if len(data) < len(expectedBoilerplate) {
		return false, nil
	}

	data = data[:len(expectedBoilerplate)]

	// Search for "Copyright YEAR" which exists in the boilerplate, but shouldn't in the real thing
	re = regexp.MustCompile(`Copyright YEAR`)
	if re.Match(data) {
		return false, nil
	}

	// Replace all occurrences of the regex "Copyright \d{4}" with "Copyright YEAR"
	re = regexp.MustCompile(`Copyright \d{4}`)
	data = re.ReplaceAll(data, []byte(`Copyright YEAR`))

	return bytes.Equal(data, expectedBoilerplate), nil
}

// filesToCheck returns the list of the filers that will be checked for the boilerplate.
func filesToCheck(rootDir string, extensions map[string][]byte) ([]string, error) {
	var outFiles []string
	err := filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error {
		// remove current workdir from the beginig of the path in case it matches the skipped path
		cwd, _ := os.Getwd()
		// replace "\" with "\\" for windows style path
		re := regexp.MustCompile(`\\`)
		re = regexp.MustCompile(`^` + re.ReplaceAllString(cwd, `\\`))
		if !info.IsDir() && !skippedPaths.MatchString(re.ReplaceAllString(filepath.Dir(path), "")) {
			if extensions[strings.ToLower(filepath.Ext(path))] != nil {
				outFiles = append(outFiles, path)
			}
		}
		return nil
	})
	if err != nil {
		return nil, err
	}
	if *verbose {
		rootDir, err = filepath.Abs(rootDir)
		if err != nil {
			return outFiles, err
		}
		fmt.Printf("Found %v files to check in %v\n\n", len(outFiles), rootDir)
	}
	return outFiles, nil
}
<|endoftext|>


<commit_before>package handler

import (
	"context"
	"fmt"
	"github.com/Comcast/webpa-common/logging"
	"github.com/Comcast/webpa-common/secure"
	"net/http"
	"os"
)

// AuthorizationHandler provides decoration for http.Handler instances and will
// ensure that requests pass the validator.  Note that secure.Validators is a Validator
// implementation that allows chaining validators together via logical OR.
type AuthorizationHandler struct {
	HeaderName          string
	ForbiddenStatusCode int
	Validator           secure.Validator
	Logger              logging.Logger
}

// headerName returns the authorization header to use, either a.HeaderName
// or secure.AuthorizationHeader if no header is supplied
func (a AuthorizationHandler) headerName() string {
	if len(a.HeaderName) > 0 {
		return a.HeaderName
	}

	return secure.AuthorizationHeader
}

// forbiddenStatusCode returns a.ForbiddenStatusCode if supplied, otherwise
// http.StatusForbidden is returned
func (a AuthorizationHandler) forbiddenStatusCode() int {
	if a.ForbiddenStatusCode > 0 {
		return a.ForbiddenStatusCode
	}

	return http.StatusForbidden
}

func (a AuthorizationHandler) logger() logging.Logger {
	if a.Logger != nil {
		return a.Logger
	}

	return &logging.LoggerWriter{os.Stdout}
}

// Decorate provides an Alice-compatible constructor that validates requests
// using the configuration specified.
func (a AuthorizationHandler) Decorate(delegate http.Handler) http.Handler {
	// if there is no validator, there's no point in decorating anything
	if a.Validator == nil {
		return delegate
	}

	headerName := a.headerName()
	forbiddenStatusCode := a.forbiddenStatusCode()
	logger := a.logger()

	return http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
		headerValue := request.Header.Get(headerName)
		if len(headerValue) == 0 {
			message := fmt.Sprintf("No %s header", headerName)
			logger.Error(message)
			WriteJsonError(response, forbiddenStatusCode, message)
			return
		}

		token, err := secure.ParseAuthorization(headerValue)
		if err != nil {
			message := fmt.Sprintf("Invalid authorization header [%s]: %s", headerName, err.Error())
			logger.Error(message)
			WriteJsonError(response, forbiddenStatusCode, message)
			return
		}

		ctx := context.Background()
		ctx = context.WithValue(ctx, "method", request.Method)
		ctx = context.WithValue(ctx, "path", request.URL.Path)

		valid, err := a.Validator.Validate(ctx, token)
		if err != nil {
			logger.Error("Validation error: %s", err.Error())
		} else if valid {
			// if any validator approves, stop and invoke the delegate
			delegate.ServeHTTP(response, request)
			return
		}

		logger.Error("Request denied: %s", request)
		response.WriteHeader(forbiddenStatusCode)
	})
}
<commit_msg>changing request denied log message in authHandler (#56)<commit_after>package handler

import (
	"context"
	"fmt"
	"github.com/Comcast/webpa-common/logging"
	"github.com/Comcast/webpa-common/secure"
	"net/http"
	"os"
)

// AuthorizationHandler provides decoration for http.Handler instances and will
// ensure that requests pass the validator.  Note that secure.Validators is a Validator
// implementation that allows chaining validators together via logical OR.
type AuthorizationHandler struct {
	HeaderName          string
	ForbiddenStatusCode int
	Validator           secure.Validator
	Logger              logging.Logger
}

// headerName returns the authorization header to use, either a.HeaderName
// or secure.AuthorizationHeader if no header is supplied
func (a AuthorizationHandler) headerName() string {
	if len(a.HeaderName) > 0 {
		return a.HeaderName
	}

	return secure.AuthorizationHeader
}

// forbiddenStatusCode returns a.ForbiddenStatusCode if supplied, otherwise
// http.StatusForbidden is returned
func (a AuthorizationHandler) forbiddenStatusCode() int {
	if a.ForbiddenStatusCode > 0 {
		return a.ForbiddenStatusCode
	}

	return http.StatusForbidden
}

func (a AuthorizationHandler) logger() logging.Logger {
	if a.Logger != nil {
		return a.Logger
	}

	return &logging.LoggerWriter{os.Stdout}
}

// Decorate provides an Alice-compatible constructor that validates requests
// using the configuration specified.
func (a AuthorizationHandler) Decorate(delegate http.Handler) http.Handler {
	// if there is no validator, there's no point in decorating anything
	if a.Validator == nil {
		return delegate
	}

	headerName := a.headerName()
	forbiddenStatusCode := a.forbiddenStatusCode()
	logger := a.logger()

	return http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
		headerValue := request.Header.Get(headerName)
		if len(headerValue) == 0 {
			message := fmt.Sprintf("No %s header", headerName)
			logger.Error(message)
			WriteJsonError(response, forbiddenStatusCode, message)
			return
		}

		token, err := secure.ParseAuthorization(headerValue)
		if err != nil {
			message := fmt.Sprintf("Invalid authorization header [%s]: %s", headerName, err.Error())
			logger.Error(message)
			WriteJsonError(response, forbiddenStatusCode, message)
			return
		}

		ctx := context.Background()
		ctx = context.WithValue(ctx, "method", request.Method)
		ctx = context.WithValue(ctx, "path", request.URL.Path)

		valid, err := a.Validator.Validate(ctx, token)
		if err != nil {
			logger.Error("Validation error: %s", err.Error())
		} else if valid {
			// if any validator approves, stop and invoke the delegate
			delegate.ServeHTTP(response, request)
			return
		}

		reqLogMsg := fmt.Sprintf("Request {Method: %s, URL: %s, User-Agent: %s, ContentLength: %d, RemoteAddr: %s}",
		                         request.Method, request.URL.String(), request.Header.Get("User-Agent"),
		                         request.ContentLength, request.RemoteAddr)

		logger.Error("Request denied: %s", reqLogMsg)
		response.WriteHeader(forbiddenStatusCode)
	})
}
<|endoftext|>


<commit_before>// Copyright 2014-2015 The DevMine 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 src

import "fmt"

const (
	IntLit    = "INT"
	FloatLit  = "FLOAT"
	ImagLit   = "IMAG"
	CharLit   = "CHAR"
	StringLit = "STRING"
)

type BasicLit struct {
	ExprName string `json:"expression_name"`
	Kind     string `json:"kind"`
	Value    string `json:"value"`
}

func newBasicLit(m map[string]interface{}) (*BasicLit, error) {
	var err error
	errPrefix := "src/basic_lit"
	basiclit := BasicLit{}

	if typ, err := extractStringValue("expression_name", errPrefix, m); err != nil {
		// XXX It is not possible to add debug info on this error because it is
		// required that this error be en "errNotExist".
		return nil, errNotExist
	} else if typ != BasicLitName {
		return nil, fmt.Errorf("invalid type: expected 'BasicLit', found '%s'", typ)
	}

	basiclit.ExprName = BasicLitName

	if basiclit.Kind, err = extractStringValue("kind", errPrefix, m); err != nil {
		return nil, err
	}

	if basiclit.Value, err = extractStringValue("value", errPrefix, m); err != nil {
		return nil, err
	}

	return &basiclit, nil
}
<commit_msg>src: add BoolLit and NilLit support<commit_after>// Copyright 2014-2015 The DevMine 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 src

import "fmt"

const (
	IntLit    = "INT"
	FloatLit  = "FLOAT"
	ImagLit   = "IMAG"
	CharLit   = "CHAR"
	StringLit = "STRING"
	BoolLit   = "BOOl"
	NilLit    = "NIL"
)

type BasicLit struct {
	ExprName string `json:"expression_name"`
	Kind     string `json:"kind"`
	Value    string `json:"value"`
}

func newBasicLit(m map[string]interface{}) (*BasicLit, error) {
	var err error
	errPrefix := "src/basic_lit"
	basiclit := BasicLit{}

	if typ, err := extractStringValue("expression_name", errPrefix, m); err != nil {
		// XXX It is not possible to add debug info on this error because it is
		// required that this error be en "errNotExist".
		return nil, errNotExist
	} else if typ != BasicLitName {
		return nil, fmt.Errorf("invalid type: expected 'BasicLit', found '%s'", typ)
	}

	basiclit.ExprName = BasicLitName

	if basiclit.Kind, err = extractStringValue("kind", errPrefix, m); err != nil {
		return nil, err
	}

	if basiclit.Value, err = extractStringValue("value", errPrefix, m); err != nil {
		return nil, err
	}

	return &basiclit, nil
}
<|endoftext|>


<commit_before>// Copyright 2020 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 pkgpath

import (
	"os"
	"testing"
)

const testEnvName = "GO_PKGPATH_TEST_COMPILER"

// This init function supports TestToSymbolFunc. For simplicity,
// we use the test binary itself as a sample gccgo driver.
// We set an environment variable to specify how it should behave.
func init() {
	switch os.Getenv(testEnvName) {
	case "":
		return
	case "v1":
		os.Stdout.WriteString(`.string	"go.l__ufer.Run"`)
		os.Exit(0)
	case "v2":
		os.Stdout.WriteString(`.string	"go.l..u00e4ufer.Run"`)
		os.Exit(0)
	case "v3":
		os.Stdout.WriteString(`.string	"go_0l_u00e4ufer.Run"`)
		os.Exit(0)
	case "error":
		os.Stdout.WriteString(`unknown string`)
		os.Exit(0)
	}
}

func TestToSymbolFunc(t *testing.T) {
	const input = "pä世🜃"
	tests := []struct {
		env     string
		fail    bool
		mangled string
	}{
		{
			env:     "v1",
			mangled: "p___",
		},
		{
			env:     "v2",
			mangled: "p..u00e4..u4e16..U0001f703",
		},
		{
			env:     "v3",
			mangled: "p_u00e4_u4e16_U0001f703",
		},
		{
			env:  "error",
			fail: true,
		},
	}

	cmd := os.Args[0]
	tmpdir := t.TempDir()

	defer os.Unsetenv(testEnvName)

	for _, test := range tests {
		t.Run(test.env, func(t *testing.T) {
			os.Setenv(testEnvName, test.env)

			fn, err := ToSymbolFunc(cmd, tmpdir)
			if err != nil {
				if !test.fail {
					t.Errorf("ToSymbolFunc(%q, %q): unexpected error %v", cmd, tmpdir, err)
				}
			} else if test.fail {
				t.Errorf("ToSymbolFunc(%q, %q) succeeded but expected to fail", cmd, tmpdir)
			} else if got, want := fn(input), test.mangled; got != want {
				t.Errorf("ToSymbolFunc(%q, %q)(%q) = %q, want %q", cmd, tmpdir, input, got, want)
			}
		})
	}
}

var symbolTests = []struct {
	input, v1, v2, v3 string
}{
	{
		"",
		"",
		"",
		"",
	},
	{
		"bytes",
		"bytes",
		"bytes",
		"bytes",
	},
	{
		"net/http",
		"net_http",
		"net..z2fhttp",
		"net_1http",
	},
	{
		"golang.org/x/net/http",
		"golang_org_x_net_http",
		"golang.x2eorg..z2fx..z2fnet..z2fhttp",
		"golang_0org_1x_1net_1http",
	},
	{
		"pä世.🜃",
		"p____",
		"p..u00e4..u4e16.x2e..U0001f703",
		"p_u00e4_u4e16_0_U0001f703",
	},
}

func TestV1(t *testing.T) {
	for _, test := range symbolTests {
		if got, want := toSymbolV1(test.input), test.v1; got != want {
			t.Errorf("toSymbolV1(%q) = %q, want %q", test.input, got, want)
		}
	}
}

func TestV2(t *testing.T) {
	for _, test := range symbolTests {
		if got, want := toSymbolV2(test.input), test.v2; got != want {
			t.Errorf("toSymbolV2(%q) = %q, want %q", test.input, got, want)
		}
	}
}

func TestV3(t *testing.T) {
	for _, test := range symbolTests {
		if got, want := toSymbolV3(test.input), test.v3; got != want {
			t.Errorf("toSymbolV3(%q) = %q, want %q", test.input, got, want)
		}
	}
}
<commit_msg>cmd/internal/pkgpath: use MustHaveExec in TestToSymbolFunc<commit_after>// Copyright 2020 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 pkgpath

import (
	"internal/testenv"
	"os"
	"testing"
)

const testEnvName = "GO_PKGPATH_TEST_COMPILER"

// This init function supports TestToSymbolFunc. For simplicity,
// we use the test binary itself as a sample gccgo driver.
// We set an environment variable to specify how it should behave.
func init() {
	switch os.Getenv(testEnvName) {
	case "":
		return
	case "v1":
		os.Stdout.WriteString(`.string	"go.l__ufer.Run"`)
		os.Exit(0)
	case "v2":
		os.Stdout.WriteString(`.string	"go.l..u00e4ufer.Run"`)
		os.Exit(0)
	case "v3":
		os.Stdout.WriteString(`.string	"go_0l_u00e4ufer.Run"`)
		os.Exit(0)
	case "error":
		os.Stdout.WriteString(`unknown string`)
		os.Exit(0)
	}
}

func TestToSymbolFunc(t *testing.T) {
	testenv.MustHaveExec(t)

	const input = "pä世🜃"
	tests := []struct {
		env     string
		fail    bool
		mangled string
	}{
		{
			env:     "v1",
			mangled: "p___",
		},
		{
			env:     "v2",
			mangled: "p..u00e4..u4e16..U0001f703",
		},
		{
			env:     "v3",
			mangled: "p_u00e4_u4e16_U0001f703",
		},
		{
			env:  "error",
			fail: true,
		},
	}

	cmd := os.Args[0]
	tmpdir := t.TempDir()

	defer os.Unsetenv(testEnvName)

	for _, test := range tests {
		t.Run(test.env, func(t *testing.T) {
			os.Setenv(testEnvName, test.env)

			fn, err := ToSymbolFunc(cmd, tmpdir)
			if err != nil {
				if !test.fail {
					t.Errorf("ToSymbolFunc(%q, %q): unexpected error %v", cmd, tmpdir, err)
				}
			} else if test.fail {
				t.Errorf("ToSymbolFunc(%q, %q) succeeded but expected to fail", cmd, tmpdir)
			} else if got, want := fn(input), test.mangled; got != want {
				t.Errorf("ToSymbolFunc(%q, %q)(%q) = %q, want %q", cmd, tmpdir, input, got, want)
			}
		})
	}
}

var symbolTests = []struct {
	input, v1, v2, v3 string
}{
	{
		"",
		"",
		"",
		"",
	},
	{
		"bytes",
		"bytes",
		"bytes",
		"bytes",
	},
	{
		"net/http",
		"net_http",
		"net..z2fhttp",
		"net_1http",
	},
	{
		"golang.org/x/net/http",
		"golang_org_x_net_http",
		"golang.x2eorg..z2fx..z2fnet..z2fhttp",
		"golang_0org_1x_1net_1http",
	},
	{
		"pä世.🜃",
		"p____",
		"p..u00e4..u4e16.x2e..U0001f703",
		"p_u00e4_u4e16_0_U0001f703",
	},
}

func TestV1(t *testing.T) {
	for _, test := range symbolTests {
		if got, want := toSymbolV1(test.input), test.v1; got != want {
			t.Errorf("toSymbolV1(%q) = %q, want %q", test.input, got, want)
		}
	}
}

func TestV2(t *testing.T) {
	for _, test := range symbolTests {
		if got, want := toSymbolV2(test.input), test.v2; got != want {
			t.Errorf("toSymbolV2(%q) = %q, want %q", test.input, got, want)
		}
	}
}

func TestV3(t *testing.T) {
	for _, test := range symbolTests {
		if got, want := toSymbolV3(test.input), test.v3; got != want {
			t.Errorf("toSymbolV3(%q) = %q, want %q", test.input, got, want)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2014-2015 The DevMine 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 src

import (
	"fmt"
	"reflect"
)

type EnumDecl struct {
	Name                  string             `json:"name"`
	Visibility            string             `json:"visibility"`
	ImplementedInterfaces []*InterfaceRef    `json:"implemented_interfaces,omitempty"`
	Attrs                 []*Attr            `json:"attributes,omitempty"`
	Constructors          []*ConstructorDecl `json:"constructors,omitempty"`
	Destructors           []*DestructorDecl  `json:"destructors,omitempty"`
	Methods               []*MethodDecl      `json:"methods,omitempty"`
}

func newEnumDecl(m map[string]interface{}) (*EnumDecl, error) {
	var err error
	errPrefix := "src/enum_decl"
	cls := EnumDecl{}

	if cls.Name, err = extractStringValue("name", errPrefix, m); err != nil {
		return nil, addDebugInfo(err)
	}

	if cls.Visibility, err = extractStringValue("visibility", errPrefix, m); err != nil {
		return nil, addDebugInfo(err)
	}

	if cls.ImplementedInterfaces, err = newInterfaceRefsSlice("implemented_interfaces", errPrefix, m); err != nil && isExist(err) {
		return nil, addDebugInfo(err)
	}

	if cls.Attrs, err = newAttrsSlice("attributes", errPrefix, m); err != nil && isExist(err) {
		return nil, addDebugInfo(err)
	}

	if cls.Constructors, err = newConstructorDeclsSlice("constructors", errPrefix, m); err != nil && isExist(err) {
		return nil, addDebugInfo(err)
	}

	if cls.Destructors, err = newDestructorDeclsSlice("destructors", errPrefix, m); err != nil && isExist(err) {
		return nil, addDebugInfo(err)
	}

	if cls.Methods, err = newMethodDeclsSlice("methods", errPrefix, m); err != nil && isExist(err) {
		return nil, addDebugInfo(err)
	}

	return &cls, nil
}

func newEnumDeclsSlice(key, errPrefix string, m map[string]interface{}) ([]*EnumDecl, error) {
	var err error
	var s reflect.Value

	clssMap, ok := m[key]
	if !ok {
		// XXX It is not possible to add debug info on this error because it is
		// required that this error be en "errNotExist".
		return nil, errNotExist
	}

	if s = reflect.ValueOf(clssMap); s.Kind() != reflect.Slice {
		return nil, addDebugInfo(fmt.Errorf(
			"%s: field '%s' is supposed to be a slice", errPrefix, key))
	}

	clss := make([]*EnumDecl, s.Len(), s.Len())
	for i := 0; i < s.Len(); i++ {
		cls := s.Index(i).Interface()

		switch cls.(type) {
		case map[string]interface{}:
			if clss[i], err = newEnumDecl(cls.(map[string]interface{})); err != nil {
				return nil, addDebugInfo(err)
			}
		default:
			return nil, addDebugInfo(fmt.Errorf(
				"%s: '%s' must be a map[string]interface{}", errPrefix, key))
		}
	}

	return clss, nil
}
<commit_msg>src: add missing EnumConstants field to EnumDecl<commit_after>// Copyright 2014-2015 The DevMine 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 src

import (
	"fmt"
	"reflect"
)

type EnumDecl struct {
	Name                  string             `json:"name"`
	Visibility            string             `json:"visibility"`
	ImplementedInterfaces []*InterfaceRef    `json:"implemented_interfaces,omitempty"`
	EnumConstants         []*Ident           `json:"enum_constants,omitempty"`
	Attrs                 []*Attr            `json:"attributes,omitempty"`
	Constructors          []*ConstructorDecl `json:"constructors,omitempty"`
	Destructors           []*DestructorDecl  `json:"destructors,omitempty"`
	Methods               []*MethodDecl      `json:"methods,omitempty"`
}

func newEnumDecl(m map[string]interface{}) (*EnumDecl, error) {
	var err error
	errPrefix := "src/enum_decl"
	cls := EnumDecl{}

	if cls.Name, err = extractStringValue("name", errPrefix, m); err != nil {
		return nil, addDebugInfo(err)
	}

	if cls.Visibility, err = extractStringValue("visibility", errPrefix, m); err != nil {
		return nil, addDebugInfo(err)
	}

	if cls.ImplementedInterfaces, err = newInterfaceRefsSlice("implemented_interfaces", errPrefix, m); err != nil && isExist(err) {
		return nil, addDebugInfo(err)
	}

	if cls.Attrs, err = newAttrsSlice("attributes", errPrefix, m); err != nil && isExist(err) {
		return nil, addDebugInfo(err)
	}

	if cls.EnumConstants, err = newIdentsSlice("enum_constants", errPrefix, m); err != nil && isExist(err) {
		return nil, addDebugInfo(err)
	}

	if cls.Constructors, err = newConstructorDeclsSlice("constructors", errPrefix, m); err != nil && isExist(err) {
		return nil, addDebugInfo(err)
	}

	if cls.Destructors, err = newDestructorDeclsSlice("destructors", errPrefix, m); err != nil && isExist(err) {
		return nil, addDebugInfo(err)
	}

	if cls.Methods, err = newMethodDeclsSlice("methods", errPrefix, m); err != nil && isExist(err) {
		return nil, addDebugInfo(err)
	}

	return &cls, nil
}

func newEnumDeclsSlice(key, errPrefix string, m map[string]interface{}) ([]*EnumDecl, error) {
	var err error
	var s reflect.Value

	clssMap, ok := m[key]
	if !ok {
		// XXX It is not possible to add debug info on this error because it is
		// required that this error be en "errNotExist".
		return nil, errNotExist
	}

	if s = reflect.ValueOf(clssMap); s.Kind() != reflect.Slice {
		return nil, addDebugInfo(fmt.Errorf(
			"%s: field '%s' is supposed to be a slice", errPrefix, key))
	}

	clss := make([]*EnumDecl, s.Len(), s.Len())
	for i := 0; i < s.Len(); i++ {
		cls := s.Index(i).Interface()

		switch cls.(type) {
		case map[string]interface{}:
			if clss[i], err = newEnumDecl(cls.(map[string]interface{})); err != nil {
				return nil, addDebugInfo(err)
			}
		default:
			return nil, addDebugInfo(fmt.Errorf(
				"%s: '%s' must be a map[string]interface{}", errPrefix, key))
		}
	}

	return clss, nil
}
<|endoftext|>


<commit_before>// Copyright 2014-2015 The DevMine 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 src

import "fmt"

type LoopStmt struct {
	StmtName   string `json:"statement_name"`
	Init       []Stmt `json:"initialization"`
	Cond       Expr   `json:"condition"`
	Post       []Stmt `json:"post_iteration_statement"`
	Body       []Stmt `json:"body"`
	Else       []Stmt `json:"else",omitempty`
	IsPostEval bool   `json:"is_post_evaluated"`
	Line       int64  `json:"line"` // Line number of the statement relatively to the function.
}

// newLoopStmt creates a new LoopStmt from a generic map.
func newLoopStmt(m map[string]interface{}) (*LoopStmt, error) {
	var err error
	errPrefix := "src/loop_stmt"
	loopstmt := LoopStmt{}

	if typ, err := extractStringValue("statement_name", errPrefix, m); err != nil {
		// XXX It is not possible to add debug info on this error because it is
		// required that this error be en "errNotExist".
		return nil, errNotExist
	} else if typ != LoopStmtName {
		return nil, fmt.Errorf("invalid type: expected 'LoopStmt', found '%s'", typ)
	}

	loopstmt.StmtName = LoopStmtName

	if loopstmt.Init, err = newStmtsSlice("initialization", errPrefix, m); err != nil {
		return nil, addDebugInfo(err)
	}

	condMap, err := extractMapValue("condition", errPrefix, m)
	if err != nil {
		return nil, addDebugInfo(err)
	}

	if loopstmt.Cond, err = newExpr(condMap); err != nil {
		return nil, addDebugInfo(err)
	}

	if loopstmt.Post, err = newStmtsSlice("post_iteration_statement", errPrefix, m); err != nil {
		return nil, addDebugInfo(err)
	}

	if loopstmt.IsPostEval, err = extractBoolValue("is_post_evaluated", errPrefix, m); err != nil {
		return nil, addDebugInfo(err)
	}

	if loopstmt.Line, err = extractInt64Value("line", errPrefix, m); err != nil {
		return nil, addDebugInfo(err)
	}

	if loopstmt.Body, err = newStmtsSlice("body", errPrefix, m); err != nil {
		return nil, addDebugInfo(err)
	}

	if loopstmt.Else, err = newStmtsSlice("else", errPrefix, m); err != nil {
		return nil, addDebugInfo(err)
	}

	return &loopstmt, nil
}
<commit_msg>src: make init and post fields of a LoopStmt optional<commit_after>// Copyright 2014-2015 The DevMine 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 src

import "fmt"

type LoopStmt struct {
	StmtName   string `json:"statement_name"`
	Init       []Stmt `json:"initialization,omitempty"`
	Cond       Expr   `json:"condition"`
	Post       []Stmt `json:"post_iteration_statement,omitempty"`
	Body       []Stmt `json:"body"`
	Else       []Stmt `json:"else",omitempty`
	IsPostEval bool   `json:"is_post_evaluated"`
	Line       int64  `json:"line"` // Line number of the statement relatively to the function.
}

// newLoopStmt creates a new LoopStmt from a generic map.
func newLoopStmt(m map[string]interface{}) (*LoopStmt, error) {
	var err error
	errPrefix := "src/loop_stmt"
	loopstmt := LoopStmt{}

	if typ, err := extractStringValue("statement_name", errPrefix, m); err != nil {
		// XXX It is not possible to add debug info on this error because it is
		// required that this error be en "errNotExist".
		return nil, errNotExist
	} else if typ != LoopStmtName {
		return nil, fmt.Errorf("invalid type: expected 'LoopStmt', found '%s'", typ)
	}

	loopstmt.StmtName = LoopStmtName

	if loopstmt.Init, err = newStmtsSlice("initialization", errPrefix, m); err != nil && isExist(err) {
		return nil, addDebugInfo(err)
	}

	condMap, err := extractMapValue("condition", errPrefix, m)
	if err != nil {
		return nil, addDebugInfo(err)
	}

	if loopstmt.Cond, err = newExpr(condMap); err != nil {
		return nil, addDebugInfo(err)
	}

	if loopstmt.Post, err = newStmtsSlice("post_iteration_statement", errPrefix, m); err != nil && isExist(err) {
		return nil, addDebugInfo(err)
	}

	if loopstmt.IsPostEval, err = extractBoolValue("is_post_evaluated", errPrefix, m); err != nil {
		return nil, addDebugInfo(err)
	}

	if loopstmt.Line, err = extractInt64Value("line", errPrefix, m); err != nil {
		return nil, addDebugInfo(err)
	}

	if loopstmt.Body, err = newStmtsSlice("body", errPrefix, m); err != nil {
		return nil, addDebugInfo(err)
	}

	if loopstmt.Else, err = newStmtsSlice("else", errPrefix, m); err != nil {
		return nil, addDebugInfo(err)
	}

	return &loopstmt, nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"fmt"
	"io"
	"net"
	"os"
	"time"
	"crypto/tls"
)

// Host:port to listen from
var from string

// Host:port to forward to
var to string

// If true, use SSL/TLS connections
var ssl bool

// Interval to collect (ms)
var interval int

// Count the connections to make them easily identifiable
var nextConnId = make(chan int)

// Timestamp format for logging
const stampf = "02.01.2006 15:04:05.000"

var events = make(chan event, 1000)

type eventKind byte
const (
	_                 = iota
	connect eventKind = iota
	disconnect
	send
	receive
)
type event struct {
	kind eventKind
	data uint32
}

type stats struct {
	stamp time.Time
	connCount uint32
	connOpened uint32
	connClosed uint32
	sent uint32
	received uint32
}

func statsCollector() {
	stats := stats{stamp: time.Now()}
	ticker := time.Tick(time.Duration(interval) * time.Millisecond)
	for {
		select {
			case e := <-events:
				switch e.kind {
					case connect:
						stats.connCount++
						stats.connOpened++
					case disconnect:
						stats.connCount--
						stats.connClosed++
					case send:
						stats.sent += e.data
					case receive:
						stats.received += e.data
				}
			case <-ticker:
				printStats(&stats)
				resetStats(&stats)
		}
	}
}

func resetStats(s *stats) {
	// Note: connCount is not reset, as we want to track the absolute value
	s.stamp = time.Now()
	s.connOpened = 0
	s.connClosed = 0
	s.sent = 0
	s.received = 0
}

func printStatHeader() {
	os.Stdout.WriteString("Date;ConnCount;ConnOpened;ConnClosed;Sent;Received;TotalTransferred\n")
}

func printStats(s *stats) {
	os.Stdout.WriteString(s.stamp.Format(stampf))
	fmt.Printf(";%d;%d;%d;%d;%d;%d\n", s.connCount, s.connOpened, s.connClosed, s.sent, s.received, s.sent + s.received)
}

type statsWriter struct {
	direction eventKind
}

func (s *statsWriter) Write(p []byte) (n int, err error) {
	events <- event{kind:s.direction, data:uint32(len(p))}
	return len(p), nil
}

// Copy to dst and to logger
func copyWithLog(dst io.Writer, src io.Reader, direction eventKind, done chan<- bool) {
	logger := &statsWriter{direction:direction}
	multi := io.MultiWriter(dst, logger)
	if _, err := io.Copy(multi, src); err != nil {
		//logPrintf("Closed connection: %v", err)
	}
	done <- true
}

func handleConnection(src net.Conn) {
	defer src.Close()

	events <- event{kind:connect}

	var dst net.Conn
	var err error
	if ssl {
		dst, err = tls.Dial("tcp", to, tlsClientConfig())
	} else {
		dst, err = net.Dial("tcp", to)
	}

	if err != nil {
		log.Panicf("Error connecting to dest: %v", err)
	}
	defer dst.Close()

	done := make(chan bool)

	// Copy & log in both directions
	go copyWithLog(dst, src, send, done)
	go copyWithLog(src, dst, receive, done)

	// Wait for connection to close
	<-done
	events <- event{kind:disconnect}
	// Wait for the other stream to close as well
	<-done
}

func tlsServerConfig() *tls.Config {
	cert, err := tls.LoadX509KeyPair("cert.pem", "key.pem")
	if err != nil {
		log.Panicf("Could not read server certificate (cert.pem, key.pem): %v", err)
	}
	return &tls.Config{Certificates: []tls.Certificate{cert}}
}

func tlsClientConfig() *tls.Config {
	// Simply accept everything
	return &tls.Config{InsecureSkipVerify: true}
}

func init() {
	flag.StringVar(&from, "from", "", "Source host/port to listen to. Example: ':8081'")
	flag.StringVar(&to, "to", "", "Destination host/port to forward to. Example: 'localhost:8080'")
	flag.BoolVar(&ssl, "ssl", false, "If true, expect and provide SSL/TLS connections. Needs cert.pem + key.pem in the same directory")
	flag.IntVar(&interval, "interval", 1000, "Interval in which to collect (ms)")
}

func main() {
	flag.Parse()
	if len(from) == 0 || len(to) == 0 {
		flag.Usage()
		os.Exit(1)
	}

	printStatHeader()
	go statsCollector()

	var ln net.Listener
	var err error
	if ssl {
		ln, err = tls.Listen("tcp", from, tlsServerConfig())
	} else {
		ln, err = net.Listen("tcp", from)
	}

	if err != nil {
		log.Panicf("Could not open port: %v", err)
	}

	for {
		conn, err := ln.Accept()
		if err != nil {
			log.Panicf("Error accepting: %v", err)
		}
		go handleConnection(conn)
	}
}
<commit_msg>Ensure all connections are closed on SIGTERM and SIGINT<commit_after>package main

import (
	"flag"
	"log"
	"fmt"
	"io"
	"net"
	"os"
	"time"
	"crypto/tls"
	"os/signal"
)

// Host:port to listen from
var from string

// Host:port to forward to
var to string

// If true, use SSL/TLS connections
var ssl bool

// Interval to collect (ms)
var interval int

// Count the connections to make them easily identifiable
var nextConnId = make(chan int)

// Timestamp format for logging
const stampf = "02.01.2006 15:04:05.000"

var events = make(chan event, 1000)

type eventKind byte
const (
	_                 = iota
	connect eventKind = iota
	disconnect
	send
	receive
)
type event struct {
	kind eventKind
	data uint32
}

type stats struct {
	stamp time.Time
	connCount uint32
	connOpened uint32
	connClosed uint32
	sent uint32
	received uint32
}

func statsCollector() {
	stats := stats{stamp: time.Now()}
	ticker := time.Tick(time.Duration(interval) * time.Millisecond)
	for {
		select {
			case e := <-events:
				switch e.kind {
					case connect:
						stats.connCount++
						stats.connOpened++
					case disconnect:
						stats.connCount--
						stats.connClosed++
					case send:
						stats.sent += e.data
					case receive:
						stats.received += e.data
				}
			case <-ticker:
				printStats(&stats)
				resetStats(&stats)
		}
	}
}

func resetStats(s *stats) {
	// Note: connCount is not reset, as we want to track the absolute value
	s.stamp = time.Now()
	s.connOpened = 0
	s.connClosed = 0
	s.sent = 0
	s.received = 0
}

func printStatHeader() {
	os.Stdout.WriteString("Date;ConnCount;ConnOpened;ConnClosed;Sent;Received;TotalTransferred\n")
}

func printStats(s *stats) {
	os.Stdout.WriteString(s.stamp.Format(stampf))
	fmt.Printf(";%d;%d;%d;%d;%d;%d\n", s.connCount, s.connOpened, s.connClosed, s.sent, s.received, s.sent + s.received)
}

type statsWriter struct {
	direction eventKind
}

func (s *statsWriter) Write(p []byte) (n int, err error) {
	events <- event{kind:s.direction, data:uint32(len(p))}
	return len(p), nil
}

// Copy to dst and to logger
func copyWithLog(dst io.Writer, src io.Reader, direction eventKind, done chan<- bool) {
	logger := &statsWriter{direction:direction}
	multi := io.MultiWriter(dst, logger)
	if _, err := io.Copy(multi, src); err != nil {
		//logPrintf("Closed connection: %v", err)
	}
	done <- true
}

func handleConnection(src net.Conn, closeConn <-chan bool, connClosed chan<- bool) {
	//defer os.Stdout.WriteString("Closed conn")
	defer func() { connClosed <- true } ()
	defer src.Close()

	events <- event{kind:connect}

	var dst net.Conn
	var err error
	if ssl {
		dst, err = tls.Dial("tcp", to, tlsClientConfig())
	} else {
		dst, err = net.Dial("tcp", to)
	}

	if err != nil {
		log.Panicf("Error connecting to dest: %v", err)
	}
	defer dst.Close()

	done := make(chan bool)

	// Copy & log in both directions
	go copyWithLog(dst, src, send, done)
	go copyWithLog(src, dst, receive, done)

	openStreams := 2

HandlerLoop:
	for {
		select {
		case <-done:
			if openStreams == 2 {
				// First stream has been closed
				events <- event{kind:disconnect}
				openStreams--
			} else {
				// Second stream has been closed -> Connection is closed, can exit
				break HandlerLoop
			}

		case <-closeConn:
			// Server signals we should close
			break HandlerLoop
		}
	}
}

func tlsServerConfig() *tls.Config {
	cert, err := tls.LoadX509KeyPair("cert.pem", "key.pem")
	if err != nil {
		log.Panicf("Could not read server certificate (cert.pem, key.pem): %v", err)
	}
	return &tls.Config{Certificates: []tls.Certificate{cert}}
}

func tlsClientConfig() *tls.Config {
	// Simply accept everything
	return &tls.Config{InsecureSkipVerify: true}
}

func listen(c chan<- net.Conn) {
	var ln net.Listener
	var err error
	if ssl {
		ln, err = tls.Listen("tcp", from, tlsServerConfig())
	} else {
		ln, err = net.Listen("tcp", from)
	}

	if err != nil {
		log.Panicf("Could not open port: %v", err)
	}

	for  {
		conn, err := ln.Accept()
		if err != nil {
			log.Panicf("Error accepting: %v", err)
		}
		c<-conn
	}
}

func server() {
	// Listen for SIGTERM (kill) and SIGINT (Ctrl+C)
	sigExit := make(chan os.Signal, 2)
	signal.Notify(sigExit, os.Interrupt, os.Kill)

	connCount := 0
	newConn := make(chan net.Conn)
	closeConn := make(chan bool)
	connClosed := make(chan bool)

	go listen(newConn)

ServerLoop:
	for {
		select {
		case c := <-newConn:
			connCount++
			go handleConnection(c, closeConn, connClosed)
		case <-connClosed:
			connCount--
		case <-sigExit:
			break ServerLoop
		}
	}

	// Signal close to all connection gorountines
	for i:=0; i<connCount; i++ {
		closeConn<-true
	}

	// Wait until all are closed (goroutines signal back)
	for i:=0; i<connCount; i++ {
		<-connClosed
	}
}

func init() {
	flag.StringVar(&from, "from", "", "Source host/port to listen to. Example: ':8081'")
	flag.StringVar(&to, "to", "", "Destination host/port to forward to. Example: 'localhost:8080'")
	flag.BoolVar(&ssl, "ssl", false, "If true, expect and provide SSL/TLS connections. Needs cert.pem + key.pem in the same directory")
	flag.IntVar(&interval, "interval", 1000, "Interval in which to collect (ms)")
}

func main() {
	flag.Parse()
	if len(from) == 0 || len(to) == 0 {
		flag.Usage()
		os.Exit(1)
	}

	printStatHeader()

	go statsCollector()
	server()

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


<commit_before>// Title：应用入口
//
// Description:
//
// Author:black
//
// Createtime:2013-08-06 13:04
//
// Version:1.0
//
// 修改历史:版本号 修改日期 修改人 修改说明
//
// 1.0 2013-08-06 13:04 black 创建文档
package main

import (
	"fmt"
	"net/http"
	"strconv"
	"github.com/hjqhezgh/lessgo"
	"server"
)

func main() {

	r := lessgo.ConfigLessgo()

	portString,_ := lessgo.Config.GetValue("lessgo","port")

	port,_ := strconv.Atoi(portString)

	r.HandleFunc("/login", server.LoginAction)

	http.Handle("/", r)

	fmt.Println("服务器监听",portString,"端口")

	lessgo.GetMySQL()

	lessgo.Log.Error(http.ListenAndServe(fmt.Sprintf(":%d", port), nil))

}
<commit_msg>添加登陆功能<commit_after>// Title：应用入口
//
// Description:
//
// Author:black
//
// Createtime:2013-08-06 13:04
//
// Version:1.0
//
// 修改历史:版本号 修改日期 修改人 修改说明
//
// 1.0 2013-08-06 13:04 black 创建文档
package main

import (
	"fmt"
	"net/http"
	"strconv"
	"github.com/hjqhezgh/lessgo"
	"server"
)

func main() {

	r := lessgo.ConfigLessgo()

	portString,_ := lessgo.Config.GetValue("lessgo","port")

	port,_ := strconv.Atoi(portString)

	r.HandleFunc("/login", server.LoginAction)

	http.Handle("/", r)

	fmt.Println("服务器监听",portString,"端口")

	lessgo.Log.Error(http.ListenAndServe(fmt.Sprintf(":%d", port), nil))

}
<|endoftext|>


<commit_before>package mc

// Handles the connection between the client and memcached servers.

import (
  "bytes"
  "encoding/binary"
  "io"
  "net"
  "sync"
  "fmt"
)

// Conn is a connection to a memcache server.
type Conn struct {
  rwc io.ReadWriteCloser
  l   sync.Mutex
  buf *bytes.Buffer
  opq uint32
}

// Dial establishes a connection to a memcache server.
func Dial(nett, addr string) (*Conn, error) {
  nc, err := net.Dial(nett, addr)
  if err != nil {
    return nil, err
  }

  cn := &Conn{rwc: nc, buf: new(bytes.Buffer)}
  return cn, nil
}

// Close closes the memcache connection.
func (cn *Conn) Close() error {
  return cn.rwc.Close()
}

// sendRecv sends and receives a complete memcache request/response exchange.
//
// LOCK INVARIANT: protected by the Conn.l lock.
func (cn *Conn) sendRecv(m *msg) (err error) {
  cn.l.Lock()
  defer cn.l.Unlock()

  err = cn.send(m)
  if err != nil {
    return
  }

  err = cn.recv(m)
  if err != nil {
    return
  }

  return nil
}

// send sends a request to the memcache server.
//
// LOCK INVARIANT: Unprotected.
func (cn *Conn) send(m *msg) (err error) {
  m.Magic = 0x80
  m.ExtraLen = sizeOfExtras(m.iextras)
  m.KeyLen = uint16(len(m.key))
  m.BodyLen = uint32(m.ExtraLen) + uint32(m.KeyLen) + uint32(len(m.val))
  m.Opaque = cn.opq
  cn.opq += 1

  // Request
  err = binary.Write(cn.buf, binary.BigEndian, m.header)
  if err != nil {
    return
  }

  for _, e := range m.iextras {
    err = binary.Write(cn.buf, binary.BigEndian, e)
    if err != nil {
      return
    }
  }

  _, err = io.WriteString(cn.buf, m.key)
  if err != nil {
    return
  }

  _, err = io.WriteString(cn.buf, m.val)
  if err != nil {
    return
  }

  _, err = cn.buf.WriteTo(cn.rwc)
  return
}

// recv receives a memcached response. It takes a msg into which to store the
// response.
//
// LOCK INVARIANT: Unprotected.
func (cn *Conn) recv(m *msg) (err error) {
  err = binary.Read(cn.rwc, binary.BigEndian, &m.header)
  if err != nil {
    return
  }

  bd := make([]byte, m.BodyLen)
  _, err = io.ReadFull(cn.rwc, bd)
  if err != nil {
    return
  }

  buf := bytes.NewBuffer(bd)

  if m.ResvOrStatus == 0 && m.ExtraLen > 0 {
    for _, e := range m.oextras {
      err = binary.Read(buf, binary.BigEndian, e)
      if err != nil {
        return
      }
    }
  }

  m.key = string(buf.Next(int(m.KeyLen)))
  vlen := int(m.BodyLen) - int(m.ExtraLen) - int(m.KeyLen)
  m.val = string(buf.Next(int(vlen)))

  return checkError(m)
}

// checkError checks if the received response is an error.
func checkError(m *msg) error {
  err, ok := errMap[m.ResvOrStatus]
  if !ok {
    return ErrUnknownError
  }
  return err
}

// sizeOfExtras returns the size of the extras field for the memcache request.
func sizeOfExtras(extras []interface{}) (l uint8) {
  for _, e := range extras {
    switch e.(type) {
    default:
      panic(fmt.Sprintf("mc: unknown extra type (%T)", e))
    case uint8:
      l += 8 / 8
    case uint16:
      l += 16 / 8
    case uint32:
      l += 32 / 8
    case uint64:
      l += 64 / 8
    }
  }
  return
}

<commit_msg>Expose connection constructor<commit_after>package mc

// Handles the connection between the client and memcached servers.

import (
  "bytes"
  "encoding/binary"
  "io"
  "net"
  "sync"
  "fmt"
)

// Conn is a connection to a memcache server.
type Conn struct {
  rwc io.ReadWriteCloser
  l   sync.Mutex
  buf *bytes.Buffer
  opq uint32
}

// Dial establishes a connection to a memcache server.
func Dial(nett, addr string) (*Conn, error) {
  nc, err := net.Dial(nett, addr)
  if err != nil {
    return nil, err
  }

  cn := NewConnection(nc)
  return cn, nil
}

func NewConnection(conn io.ReadWriteCloser) *Conn {
  return &Conn{rwc: conn, buf: new(bytes.Buffer)}
}

// Close closes the memcache connection.
func (cn *Conn) Close() error {
  return cn.rwc.Close()
}

// sendRecv sends and receives a complete memcache request/response exchange.
//
// LOCK INVARIANT: protected by the Conn.l lock.
func (cn *Conn) sendRecv(m *msg) (err error) {
  cn.l.Lock()
  defer cn.l.Unlock()

  err = cn.send(m)
  if err != nil {
    return
  }

  err = cn.recv(m)
  if err != nil {
    return
  }

  return nil
}

// send sends a request to the memcache server.
//
// LOCK INVARIANT: Unprotected.
func (cn *Conn) send(m *msg) (err error) {
  m.Magic = 0x80
  m.ExtraLen = sizeOfExtras(m.iextras)
  m.KeyLen = uint16(len(m.key))
  m.BodyLen = uint32(m.ExtraLen) + uint32(m.KeyLen) + uint32(len(m.val))
  m.Opaque = cn.opq
  cn.opq += 1

  // Request
  err = binary.Write(cn.buf, binary.BigEndian, m.header)
  if err != nil {
    return
  }

  for _, e := range m.iextras {
    err = binary.Write(cn.buf, binary.BigEndian, e)
    if err != nil {
      return
    }
  }

  _, err = io.WriteString(cn.buf, m.key)
  if err != nil {
    return
  }

  _, err = io.WriteString(cn.buf, m.val)
  if err != nil {
    return
  }

  _, err = cn.buf.WriteTo(cn.rwc)
  return
}

// recv receives a memcached response. It takes a msg into which to store the
// response.
//
// LOCK INVARIANT: Unprotected.
func (cn *Conn) recv(m *msg) (err error) {
  err = binary.Read(cn.rwc, binary.BigEndian, &m.header)
  if err != nil {
    return
  }

  bd := make([]byte, m.BodyLen)
  _, err = io.ReadFull(cn.rwc, bd)
  if err != nil {
    return
  }

  buf := bytes.NewBuffer(bd)

  if m.ResvOrStatus == 0 && m.ExtraLen > 0 {
    for _, e := range m.oextras {
      err = binary.Read(buf, binary.BigEndian, e)
      if err != nil {
        return
      }
    }
  }

  m.key = string(buf.Next(int(m.KeyLen)))
  vlen := int(m.BodyLen) - int(m.ExtraLen) - int(m.KeyLen)
  m.val = string(buf.Next(int(vlen)))

  return checkError(m)
}

// checkError checks if the received response is an error.
func checkError(m *msg) error {
  err, ok := errMap[m.ResvOrStatus]
  if !ok {
    return ErrUnknownError
  }
  return err
}

// sizeOfExtras returns the size of the extras field for the memcache request.
func sizeOfExtras(extras []interface{}) (l uint8) {
  for _, e := range extras {
    switch e.(type) {
    default:
      panic(fmt.Sprintf("mc: unknown extra type (%T)", e))
    case uint8:
      l += 8 / 8
    case uint16:
      l += 16 / 8
    case uint32:
      l += 32 / 8
    case uint64:
      l += 64 / 8
    }
  }
  return
}

<|endoftext|>


<commit_before>//usr/bin/env go run $0 "$@" ; exit

package main

import (
	"flag"
	"fmt"
	"net/smtp"
	"os"
	"strings"

	"github.com/jordan-wright/email"
)

// List makes a slice from a coma separated list:
// - list: coma separated list
// Return: list as a slice.
func List(list string) []string {
	result := strings.Split(list, ",")
	for index, element := range result {
		result[index] = strings.TrimSpace(element)
	}
	return result
}

// SendMail sends an email:
// - server: the SMTP server address (such as 'smtp.orange.fr:25')
// - from: the email sender (such as 'test@example.com').
// - to: the email recipient(s) as a coma separated list.
// - cc: carbon copy recipient(s) as a coma separated list.
// - bcc: blind carbon copy recipient(s) as a coma separated list.
// - subject: the email subject.
// - text: the email text.
// - attach: email attachment as a file path.
// - user: SMTP server user name.
// - password: the SMTP server password.
// - html: tells if email is HTML.
func SendMail(server, from, to, cc, bcc, subject, text, attach, user, pass string, html bool) error {
	mail := email.NewEmail()
	mail.From = from
	mail.To = List(to)
	if cc != "" {
		mail.Cc = List(cc)
	}
	if bcc != "" {
		mail.Bcc = List(bcc)
	}
	mail.Subject = subject
	if html {
		mail.HTML = []byte(text)
	} else {
		mail.Text = []byte(text)
	}
	if attach != "" {
		if _, err := os.Stat(attach); os.IsNotExist(err) {
			return fmt.Errorf("attachement file '%s' not found", attach)
		}
		mail.AttachFile(attach)
	}
	var auth smtp.Auth
	if user != "" {
		host := server[:strings.LastIndex(server, ":")]
		auth = smtp.PlainAuth("", user, pass, host)
	}
	return mail.Send(server, auth)
}

func main() {
	smtp := flag.String("smtp", "", "smtp server ('smtp.example.com:25')")
	from := flag.String("from", "", "mail sender")
	to := flag.String("to", "", "coma separated list of mail recipients")
	cc := flag.String("cc", "", "coma separated list of carbon copy recipients")
	bcc := flag.String("bcc", "", "coma separated list of blind carbon copy recipients")
	subject := flag.String("subject", "", "mail subject")
	html := flag.Bool("html", false, "html email message")
	attach := flag.String("attach", "", "file to attach to the mail")
	user := flag.String("user", "", "user name for authentication")
	pass := flag.String("pass", "", "user password for authentication")
	flag.Parse()
	text := strings.Join(flag.Args(), " ")
	err := SendMail(*smtp, *from, *to, *cc, *bcc, *subject, text, *attach, *user, *pass, *html)
	if err != nil {
		println(fmt.Sprintf("ERROR sending mail: %v", err))
		os.Exit(1)
	}
}
<commit_msg>Fixed bug when bad host<commit_after>//usr/bin/env go run $0 "$@" ; exit

package main

import (
	"flag"
	"fmt"
	"net/smtp"
	"os"
	"strings"

	"github.com/jordan-wright/email"
)

// List makes a slice from a coma separated list:
// - list: coma separated list
// Return: list as a slice.
func List(list string) []string {
	result := strings.Split(list, ",")
	for index, element := range result {
		result[index] = strings.TrimSpace(element)
	}
	return result
}

// SendMail sends an email:
// - server: the SMTP server address (such as 'smtp.orange.fr:25')
// - from: the email sender (such as 'test@example.com').
// - to: the email recipient(s) as a coma separated list.
// - cc: carbon copy recipient(s) as a coma separated list.
// - bcc: blind carbon copy recipient(s) as a coma separated list.
// - subject: the email subject.
// - text: the email text.
// - attach: email attachment as a file path.
// - user: SMTP server user name.
// - password: the SMTP server password.
// - html: tells if email is HTML.
func SendMail(server, from, to, cc, bcc, subject, text, attach, user, pass string, html bool) error {
	mail := email.NewEmail()
	mail.From = from
	mail.To = List(to)
	if cc != "" {
		mail.Cc = List(cc)
	}
	if bcc != "" {
		mail.Bcc = List(bcc)
	}
	mail.Subject = subject
	if html {
		mail.HTML = []byte(text)
	} else {
		mail.Text = []byte(text)
	}
	if attach != "" {
		if _, err := os.Stat(attach); os.IsNotExist(err) {
			return fmt.Errorf("attachement file '%s' not found", attach)
		}
		mail.AttachFile(attach)
	}
	var auth smtp.Auth
	if user != "" {
		index := strings.LastIndex(server, ":")
		if index == -1 {
			return fmt.Errorf("smtp must be like hostname:port, no port found")
		}
		host := server[:index]
		auth = smtp.PlainAuth("", user, pass, host)
	}
	return mail.Send(server, auth)
}

func main() {
	smtp := flag.String("smtp", "", "smtp server ('smtp.example.com:25')")
	from := flag.String("from", "", "mail sender")
	to := flag.String("to", "", "coma separated list of mail recipients")
	cc := flag.String("cc", "", "coma separated list of carbon copy recipients")
	bcc := flag.String("bcc", "", "coma separated list of blind carbon copy recipients")
	subject := flag.String("subject", "", "mail subject")
	html := flag.Bool("html", false, "html email message")
	attach := flag.String("attach", "", "file to attach to the mail")
	user := flag.String("user", "", "user name for authentication")
	pass := flag.String("pass", "", "user password for authentication")
	flag.Parse()
	text := strings.Join(flag.Args(), " ")
	err := SendMail(*smtp, *from, *to, *cc, *bcc, *subject, text, *attach, *user, *pass, *html)
	if err != nil {
		println(fmt.Sprintf("ERROR sending mail: %v", err))
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package util

import (
	"fmt"
	"io/ioutil"
	"log"
	"path/filepath"
	"regexp"
	"os"
	//"strings"
	"github.com/russross/blackfriday"
	"html/template"
	"net/http"
)
var (
	docPath    = "/Users/memee/Downloads/svn/ps-fe"
	ignoreDirs = []string{"img", ".git", ".svn", "courseware", "headline", "imgs", "js", "less", "assets"}
	mdReg = ".+.md$"
	// /^\s*#+\s?([^#\r\n]+)/
	titleReg = regexp.MustCompile("^\\s*#+\\s?([^#\\r\\n]+)")
	// /<title>(.+?)<\/title>/
	htmlTitleReg = regexp.MustCompile("<title>(.+?)<\\/title>")
)

type fileCache struct {
	title string
	path string
	ty string
	child *[]fileCache
}

var docTree = make([]fileCache,0)

type fileTrasName  map[string]string

var fileNameMap = fileTrasName{}

func ReadDirRs() []fileCache{
	// 测试数据
	fileNameMap = fileTrasName{
		"aladdin":"阿拉丁",
		"www":"搜索结果页",
		"standards":"规范流程",
		"superframe":"superframe",
		"log":"日志",
		"transcode":"无线转码",
		"realtime":"时效性",
		"performance":"性能优化",
		"references":"资源引入",
		"data":"数据接口",
		"tools":"工具服务",
		"xueshu":"学术",
		"advertise":"广告",
		"rules":"规范",
		"santa":"圣玛利亚",
		"cardspeedup":"模板性能优化",
		"commonupdate":"通用升级",
		"develop":"圣玛利亚",
		"jscommmon":"js组件",
		"platform":"平台指南",
		"publish":"上线",
		"standard":"开发规范",
		"technicalarea":"技术专区",
		"tongji":"日志",
		"wise":"无线网页搜索",
		"devdocs":"开发指导",
		"static":"静态文件",
		"pc":"PC网页搜索",
		"midpage":"搜索中间页",
		"show":"展现日志",
		"click":"点击日志",
		"client":"客户端相关规范",
		"process":"使用和变更流程",
		"action":"异步日志",
		"framework":"架构",
		"aladdin-debug":"阿拉丁常见调试",
		"research":"技术调研",
		"courseware":"串讲文档",
		"grid":"栅格化",
		"general-dev":"通用开发相关",
		"frontend-dev":"前端开发相关",
		"environment-dev":"环境相关",
		"union":"联盟相关",
		"front-interface":"前后端接口",
		"refactor":"重构",
		"test":"测试相关",
		"async":"异步化",
		"spec":"规范",
		"component":"功能组件",
		"sample":"抽样相关",
		"schema":"Schemas标记",
		"aladdin-test":"阿拉丁（测试）",
		"tpldev":"开发平台",
		"wireless-dev":"无线开发",
		"new-reading":"新人必读",
		"pc-doc":"PC开发文档",
		"team":"团队介绍",
		"pc-other":"PC其他开发文档",
		"0-send-guide":"发送指南",
		"1-stat-guide":"统计指南",
		"todolist":"备忘列表",
		"pcspans":"PCspans",
		"pcuijs":"PC-js组件",
		"paduijs":"PAD组件",
		"pclog":"PC日志",
	}

	makeDomTree(docPath, &docTree)
	// sep := string(filepath.Separator)
	// docPathReg := regexp.MustCompile(docPath)
	// filepath.Walk(docPath, func (fPath string, info os.FileInfo, err error) error {
	// 	relPath := docPathReg.ReplaceAllString(fPath, "")
	// 	justDir := filepath.Dir(relPath)
	// 	pathArr := strings.Split(justDir, sep)
	// 	fmt.Println(relPath,"~~~~",pathArr)
	// 	return nil
	// })

	return docTree

	// fmt.Println(docTree, cap(docTree), len(docTree))
}

func makeDomTree (crtPath string, ctt *[]fileCache) {
	files, err := ioutil.ReadDir(crtPath)
	if err != nil {
		log.Fatal(err)
	}

	for _, file := range files {
		fc := fileCache{}
		isDir := file.IsDir()
		docName := file.Name()

		// 文件夹需要递归处理，文件则直接存容器
		if isDir {
			//fmt.Println("file",file.Name())
			fileName := file.Name()
			//hitted := indexOf(ignoreDirs, fileName)
			//if hitted > -1 {
				subFileCache := make([]fileCache, 0)

				// 如果在目录map内有值，则目录名为设定值，没有则默认为文件夹名
				fc.title = fileName
				if fileNameMap[fileName] != "" {
					fc.title = fileNameMap[fileName]
				}

				fc.path = fileName
				fc.ty = "dir"
				fc.child = &subFileCache
				*ctt = append(*ctt, fc)

				makeDomTree(filepath.Join(crtPath, file.Name()), fc.child)
			//}
		} else {
			fc.path = filepath.Join(docPath, docName)
			isMd, err := regexp.MatchString(mdReg, fc.path)
			extName := filepath.Ext(fc.path)
			if err == nil {
				if isMd || extName == ".html" || extName == ".htm"{
					content := GetConent(fc.path)
					fc.title = GetTitle(extName, content)
					fc.ty = "file"
					// markdown转换html
					ConvMd(content)
					*ctt = append(*ctt, fc)
				}
			}
		}
	}
}

func MakeNav(treeData *[]fileCache) string{
	htmlStr := ""
	makeNavHtml(&htmlStr, treeData)

	fmt.Println("htmlStr", htmlStr)

	return htmlStr
}

/*
makeNav: function (dirs) {
        if (Array.isArray(dirs) && dirs.length) {
            for(var i = 0; i< dirs.length; i++) {
                var item = dirs[i] || {};
                if (!item) {
                    continue;
                }
                if (item.type === 'file') {
                    htmlStr += '
' + item.title + '
';
                }
                else if (item.type === 'dir') {
                    htmlStr += '
' + item.displayName + '
';
                    this.makeNav(item.child);
                    htmlStr += '

';
                }
            }
        }
    }
*/
func makeNavHtml (str *string, data *[]fileCache) {
	for _, v := range *data {
		fileType := v.ty
		if fileType == "file" {
			*str += "
" + v.title + "
"
		} else if fileType == "dir" {
			*str += "
" + v.title + "
"
			makeNavHtml(str, v.child)
			*str += "

"
		}
	}
}

// 获取最终html字符串
func GetRsHTML (path string) []byte{
	content := GetConent(path)
	rsHtml := ConvMd(content)
	return rsHtml
}

// md转html
func ConvMd(content []byte) []byte{
	output := blackfriday.MarkdownBasic(content)
	//ioutil.WriteFile(".+.md$", output, 0777)
	return output
}

// 获取标题
func GetTitle(extName string, content []byte) string {
	contentStr := string(content)
	var title string
	if extName == ".md" {
		title = titleReg.FindString(contentStr)
	} else if extName == ".html" || extName == ".htm" {
		title = htmlTitleReg.FindString(contentStr)
	}
	return title
}

// 获取文档内容
func GetConent(path string) []byte {
	nocontent := []byte("")
	stat, _ := PathExists(path)

	if stat {
		content, err := ioutil.ReadFile(path)

		if err != nil {
			log.Fatal(err)
		}
		return content
	}
	return nocontent
}

// 判断文件是否存在
func PathExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}

// 渲染模板
func RenderTpl(path string, data interface{}, w http.ResponseWriter) {
	t, err := template.ParseFiles(path)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	t.Execute(w, data)
}

// 检测文件是否存在
func isExists(path string) bool {
	_, err := os.Stat(path)
	if err != nil {
		return true
	}
	return os.IsExist(err)
}

// []string indexOf
func indexOf(s []string, oriVal string) int{
	for idx, val := range s {
		if val == oriVal {
			return idx
		}
	}
	return -1
}<commit_msg>update new docx<commit_after>package util

import (
	"fmt"
	"io/ioutil"
	"log"
	"path/filepath"
	"regexp"
	"os"
	//"strings"
	"github.com/russross/blackfriday"
	"html/template"
	"net/http"
)
var (
	docPath    = "/Users/memee/Downloads/svn/ps-fe"
	ignoreDirs = []string{"img", ".git", ".svn", "courseware", "headline", "imgs", "js", "less", "assets"}
	mdReg = ".+.md$"
	// /^\s*#+\s?([^#\r\n]+)/
	titleReg = regexp.MustCompile("^\\s*#+\\s?([^#\\r\\n]+)")
	// /<title>(.+?)<\/title>/
	htmlTitleReg = regexp.MustCompile("<title>(.+?)<\\/title>")
)

type fileCache struct {
	title string
	path string
	ty string
	child *[]fileCache
}

var docTree = make([]fileCache,0)

type fileTrasName  map[string]string

var fileNameMap = fileTrasName{}

func ReadDirRs() []fileCache{
	// 测试数据
	fileNameMap = fileTrasName{
		"aladdin":"阿拉丁",
		"www":"搜索结果页",
		"standards":"规范流程",
		"superframe":"superframe",
		"log":"日志",
		"transcode":"无线转码",
		"realtime":"时效性",
		"performance":"性能优化",
		"references":"资源引入",
		"data":"数据接口",
		"tools":"工具服务",
		"xueshu":"学术",
		"advertise":"广告",
		"rules":"规范",
		"santa":"圣玛利亚",
		"cardspeedup":"模板性能优化",
		"commonupdate":"通用升级",
		"develop":"圣玛利亚",
		"jscommmon":"js组件",
		"platform":"平台指南",
		"publish":"上线",
		"standard":"开发规范",
		"technicalarea":"技术专区",
		"tongji":"日志",
		"wise":"无线网页搜索",
		"devdocs":"开发指导",
		"static":"静态文件",
		"pc":"PC网页搜索",
		"midpage":"搜索中间页",
		"show":"展现日志",
		"click":"点击日志",
		"client":"客户端相关规范",
		"process":"使用和变更流程",
		"action":"异步日志",
		"framework":"架构",
		"aladdin-debug":"阿拉丁常见调试",
		"research":"技术调研",
		"courseware":"串讲文档",
		"grid":"栅格化",
		"general-dev":"通用开发相关",
		"frontend-dev":"前端开发相关",
		"environment-dev":"环境相关",
		"union":"联盟相关",
		"front-interface":"前后端接口",
		"refactor":"重构",
		"test":"测试相关",
		"async":"异步化",
		"spec":"规范",
		"component":"功能组件",
		"sample":"抽样相关",
		"schema":"Schemas标记",
		"aladdin-test":"阿拉丁（测试）",
		"tpldev":"开发平台",
		"wireless-dev":"无线开发",
		"new-reading":"新人必读",
		"pc-doc":"PC开发文档",
		"team":"团队介绍",
		"pc-other":"PC其他开发文档",
		"0-send-guide":"发送指南",
		"1-stat-guide":"统计指南",
		"todolist":"备忘列表",
		"pcspans":"PCspans",
		"pcuijs":"PC-js组件",
		"paduijs":"PAD组件",
		"pclog":"PC日志",
	}

	makeDomTree(docPath, &docTree)
	return docTree

	// fmt.Println(docTree, cap(docTree), len(docTree))
}

func makeDomTree (crtPath string, ctt *[]fileCache) {
	files, err := ioutil.ReadDir(crtPath)
	if err != nil {
		log.Fatal(err)
	}

	for _, file := range files {
		fc := fileCache{}
		isDir := file.IsDir()
		docName := file.Name()

		// 文件夹需要递归处理，文件则直接存容器
		if isDir {
			//fmt.Println("file",file.Name())
			fileName := file.Name()
			hitted := indexOf(ignoreDirs, fileName)
			if !hitted {
				subFileCache := make([]fileCache, 0)

				// 如果在目录map内有值，则目录名为设定值，没有则默认为文件夹名
				fc.title = fileName
				if fileNameMap[fileName] != "" {
					fc.title = fileNameMap[fileName]
				}

				fc.path = fileName
				fc.ty = "dir"
				fc.child = &subFileCache
				*ctt = append(*ctt, fc)

				makeDomTree(filepath.Join(crtPath, file.Name()), fc.child)
			}
		} else {
			fc.path = docName
			isMd, err := regexp.MatchString(mdReg, fc.path)
			extName := filepath.Ext(fc.path)
			if err == nil {
				if isMd || extName == ".html" || extName == ".htm"{
					content := GetConent(fc.path)
					fc.title = GetTitle(extName, content)
					fc.ty = "file"
					// markdown转换html
					ConvMd(content)
					*ctt = append(*ctt, fc)
				}
			}
		}
	}
}

func MakeNav(treeData *[]fileCache) string{
	htmlStr := ""
	makeNavHtml(&htmlStr, treeData)
	fmt.Println("htmlStr", htmlStr)
	return htmlStr
}

// 生成目录树，TODO: 使用template
func makeNavHtml (str *string, data *[]fileCache) {
	for _, v := range *data {
		fileType := v.ty
		if fileType == "file" {
			*str += "
" + v.title + "
"
		} else if fileType == "dir" {
			*str += "
" + v.title + "
"
			makeNavHtml(str, v.child)
			*str += "

"
		}
	}
}

// 获取最终html字符串
func GetRsHTML (path string) []byte{
	content := GetConent(path)
	rsHtml := ConvMd(content)
	return rsHtml
}

// md转html
func ConvMd(content []byte) []byte{
	output := blackfriday.MarkdownBasic(content)
	//ioutil.WriteFile(".+.md$", output, 0777)
	return output
}

// 获取标题
func GetTitle(extName string, content []byte) string {
	contentStr := string(content)
	var title string
	if extName == ".md" {
		title = titleReg.FindString(contentStr)
	} else if extName == ".html" || extName == ".htm" {
		title = htmlTitleReg.FindString(contentStr)
	}
	return title
}

// 获取文档内容
func GetConent(path string) []byte {
	nocontent := []byte("")
	stat, _ := PathExists(path)

	if stat {
		content, err := ioutil.ReadFile(path)

		if err != nil {
			log.Fatal(err)
		}
		return content
	}
	return nocontent
}

// 判断文件是否存在
func PathExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}

// 渲染模板
func RenderTpl(path string, data interface{}, w http.ResponseWriter) {
	t, err := template.ParseFiles(path)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	t.Execute(w, data)
}

// 检测文件是否存在
func isExists(path string) bool {
	_, err := os.Stat(path)
	if err != nil {
		return true
	}
	return os.IsExist(err)
}

// []string indexOf
func indexOf(s []string, oriVal string) bool{
	for _, val := range s {
		if val == oriVal {
			return true
		}
	}
	return false
}<|endoftext|>


<commit_before>package dburl

import (
	"fmt"
	"sort"
)

// Proto are the allowed transport protocol types in a database URL scheme.
type Proto uint

// Proto types.
const (
	ProtoNone Proto = 0
	ProtoTCP  Proto = 1
	ProtoUDP  Proto = 2
	ProtoUnix Proto = 4
	ProtoAny  Proto = 8
)

// Scheme wraps information used for registering a URL scheme with
// Parse/Open.
type Scheme struct {
	// Driver is the name of the SQL driver that will set as the Scheme in
	// Parse'd URLs, and is the driver name expected by the standard sql.Open
	// calls.
	//
	// Note: a 2 letter alias will always be registered for the Driver as the
	// first 2 characters of the Driver, unless one of the Aliases includes an
	// alias that is 2 characters.
	Driver string

	// Generator is the func responsible for generating a DSN based on parsed
	// URL information.
	//
	// Note: this func should not modify the passed URL.
	Generator func(*URL) (string, error)

	// Proto are allowed protocol types for the scheme.
	Proto Proto

	// Opaque toggles Parse to not re-process URLs with an "opaque" component.
	Opaque bool

	// Aliases are any additional aliases for the scheme.
	Aliases []string

	// Override is the Go SQL driver to use instead of Driver.
	Override string
}

// BaseSchemes returns the supported base schemes.
func BaseSchemes() []Scheme {
	return []Scheme{
		// core databases
		{"mssql", GenSQLServer, 0, false, []string{"sqlserver"}, ""},
		{"mysql", GenMySQL, ProtoTCP | ProtoUDP | ProtoUnix, false, []string{"mariadb", "maria", "percona", "aurora"}, ""},
		{"ora", GenOracle, 0, false, []string{"oracle", "oci8", "oci"}, ""},
		{"postgres", GenPostgres, ProtoUnix, false, []string{"pg", "postgresql", "pgsql"}, ""},
		{"sqlite3", GenOpaque, 0, true, []string{"sqlite", "file"}, ""},

		// wire compatibles
		{"cockroachdb", GenFromURL("postgres://localhost:26257/?sslmode=disable"), 0, false, []string{"cr", "cockroach", "crdb", "cdb"}, "postgres"},
		{"memsql", GenMySQL, 0, false, nil, "mysql"},
		{"tidb", GenMySQL, 0, false, nil, "mysql"},
		{"vitess", GenMySQL, 0, false, []string{"vt"}, "mysql"},

		// testing
		{"spanner", GenScheme("spanner"), 0, false, []string{"gs", "google", "span"}, ""},

		// alternates implementations
		{"mymysql", GenMyMySQL, ProtoTCP | ProtoUDP | ProtoUnix, false, []string{"zm", "mymy"}, ""},
		{"pgx", GenScheme("postgres"), ProtoUnix, false, []string{"px"}, ""},

		// other databases
		{"adodb", GenADODB, 0, false, []string{"ado"}, ""},
		{"avatica", GenFromURL("http://localhost:8765/"), 0, false, []string{"phoenix"}, ""},
		{"clickhouse", GenClickhouse, 0, false, []string{"ch"}, ""},
		{"firebirdsql", GenFirebird, 0, false, []string{"fb", "firebird"}, ""},
		{"hdb", GenScheme("hdb"), 0, false, []string{"sa", "saphana", "sap", "hana"}, ""},
		{"n1ql", GenFromURL("http://localhost:9000/"), 0, false, []string{"couchbase"}, ""},
		{"odbc", GenODBC, ProtoAny, false, nil, ""},
		{"oleodbc", GenOLEODBC, ProtoAny, false, []string{"oo", "ole"}, "adodb"},
		{"presto", GenScheme("http"), 0, false, []string{"pr", "prestodb"}, ""},
		{"ql", GenOpaque, 0, true, []string{"ql", "cznic", "cznicql"}, ""},
		{"sqlany", GenSybase, 0, false, []string{"sy", "sybase", "any"}, ""},
		{"voltdb", GenVoltDB, 0, false, []string{"volt", "vdb"}, ""},
	}
}

func init() {
	schemes := BaseSchemes()
	schemeMap = make(map[string]*Scheme, len(schemes))

	// register
	for _, scheme := range schemes {
		Register(scheme)
	}
}

// schemeMap is the map of registered schemes.
var schemeMap map[string]*Scheme

// registerAlias registers a alias for an already registered Scheme.
func registerAlias(name, alias string, doSort bool) {
	scheme, ok := schemeMap[name]
	if !ok {
		panic(fmt.Sprintf("scheme %s not registered", name))
	}

	if doSort && has(scheme.Aliases, alias) {
		panic(fmt.Sprintf("scheme %s already has alias %s", name, alias))
	}

	if _, ok := schemeMap[alias]; ok {
		panic(fmt.Sprintf("scheme %s already registered", alias))
	}

	scheme.Aliases = append(scheme.Aliases, alias)
	if doSort {
		sort.Sort(ss(scheme.Aliases))
	}

	schemeMap[alias] = scheme
}

// Register registers a Scheme.
func Register(scheme Scheme) {
	if scheme.Generator == nil {
		panic("must specify Generator when registering Scheme")
	}

	if scheme.Opaque && scheme.Proto&ProtoUnix != 0 {
		panic("scheme must support only Opaque or Unix protocols, not both")
	}

	// register
	if _, ok := schemeMap[scheme.Driver]; ok {
		panic(fmt.Sprintf("scheme %s already registered", scheme.Driver))
	}

	sz := &Scheme{
		Driver:    scheme.Driver,
		Generator: scheme.Generator,
		Proto:     scheme.Proto,
		Opaque:    scheme.Opaque,
		Override:  scheme.Override,
	}

	schemeMap[scheme.Driver] = sz

	// add aliases
	var hasShort bool
	for _, alias := range scheme.Aliases {
		if len(alias) == 2 {
			hasShort = true
		}
		if scheme.Driver != alias {
			registerAlias(scheme.Driver, alias, false)
		}
	}

	if !hasShort && len(scheme.Driver) > 2 {
		registerAlias(scheme.Driver, scheme.Driver[:2], false)
	}

	// ensure always at least one alias, and that if Driver is 2 characters,
	// that it gets added as well
	if len(sz.Aliases) == 0 || len(scheme.Driver) == 2 {
		sz.Aliases = append(sz.Aliases, scheme.Driver)
	}

	// sort
	sort.Sort(ss(sz.Aliases))
}

// Unregister unregisters a Scheme and all associated aliases.
func Unregister(name string) *Scheme {
	scheme, ok := schemeMap[name]
	if ok {
		for _, alias := range scheme.Aliases {
			delete(schemeMap, alias)
		}
		delete(schemeMap, name)
		return scheme
	}
	return nil
}

// RegisterAlias registers a alias for an already registered Scheme.h
func RegisterAlias(name, alias string) {
	registerAlias(name, alias, true)
}

// has is a util func to determine if a contains b.
func has(a []string, b string) bool {
	for _, s := range a {
		if s == b {
			return true
		}
	}

	return false
}

// SchemeDriverAndAliases returns the registered driver and aliases for a
// database scheme.
func SchemeDriverAndAliases(name string) (string, []string) {
	if scheme, ok := schemeMap[name]; ok {
		driver := scheme.Driver
		if scheme.Override != "" {
			driver = scheme.Override
		}

		var aliases []string
		for _, alias := range scheme.Aliases {
			if alias == driver {
				continue
			}
			aliases = append(aliases, alias)
		}

		sort.Sort(ss(aliases))

		return driver, aliases
	}

	return "", nil
}

// ss is a util type to provide sorting of a string slice (used for sorting
// aliases).
type ss []string

func (s ss) Len() int      { return len(s) }
func (s ss) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s ss) Less(i, j int) bool {
	if len(s[i]) <= len(s[j]) {
		return true
	}

	if len(s[j]) < len(s[i]) {
		return false
	}

	return s[i] < s[j]
}
<commit_msg>Fixing presto alias<commit_after>package dburl

import (
	"fmt"
	"sort"
)

// Proto are the allowed transport protocol types in a database URL scheme.
type Proto uint

// Proto types.
const (
	ProtoNone Proto = 0
	ProtoTCP  Proto = 1
	ProtoUDP  Proto = 2
	ProtoUnix Proto = 4
	ProtoAny  Proto = 8
)

// Scheme wraps information used for registering a URL scheme with
// Parse/Open.
type Scheme struct {
	// Driver is the name of the SQL driver that will set as the Scheme in
	// Parse'd URLs, and is the driver name expected by the standard sql.Open
	// calls.
	//
	// Note: a 2 letter alias will always be registered for the Driver as the
	// first 2 characters of the Driver, unless one of the Aliases includes an
	// alias that is 2 characters.
	Driver string

	// Generator is the func responsible for generating a DSN based on parsed
	// URL information.
	//
	// Note: this func should not modify the passed URL.
	Generator func(*URL) (string, error)

	// Proto are allowed protocol types for the scheme.
	Proto Proto

	// Opaque toggles Parse to not re-process URLs with an "opaque" component.
	Opaque bool

	// Aliases are any additional aliases for the scheme.
	Aliases []string

	// Override is the Go SQL driver to use instead of Driver.
	Override string
}

// BaseSchemes returns the supported base schemes.
func BaseSchemes() []Scheme {
	return []Scheme{
		// core databases
		{"mssql", GenSQLServer, 0, false, []string{"sqlserver"}, ""},
		{"mysql", GenMySQL, ProtoTCP | ProtoUDP | ProtoUnix, false, []string{"mariadb", "maria", "percona", "aurora"}, ""},
		{"ora", GenOracle, 0, false, []string{"oracle", "oci8", "oci"}, ""},
		{"postgres", GenPostgres, ProtoUnix, false, []string{"pg", "postgresql", "pgsql"}, ""},
		{"sqlite3", GenOpaque, 0, true, []string{"sqlite", "file"}, ""},

		// wire compatibles
		{"cockroachdb", GenFromURL("postgres://localhost:26257/?sslmode=disable"), 0, false, []string{"cr", "cockroach", "crdb", "cdb"}, "postgres"},
		{"memsql", GenMySQL, 0, false, nil, "mysql"},
		{"tidb", GenMySQL, 0, false, nil, "mysql"},
		{"vitess", GenMySQL, 0, false, []string{"vt"}, "mysql"},

		// testing
		{"spanner", GenScheme("spanner"), 0, false, []string{"gs", "google", "span"}, ""},

		// alternates implementations
		{"mymysql", GenMyMySQL, ProtoTCP | ProtoUDP | ProtoUnix, false, []string{"zm", "mymy"}, ""},
		{"pgx", GenScheme("postgres"), ProtoUnix, false, []string{"px"}, ""},

		// other databases
		{"adodb", GenADODB, 0, false, []string{"ado"}, ""},
		{"avatica", GenFromURL("http://localhost:8765/"), 0, false, []string{"phoenix"}, ""},
		{"clickhouse", GenClickhouse, 0, false, []string{"ch"}, ""},
		{"firebirdsql", GenFirebird, 0, false, []string{"fb", "firebird"}, ""},
		{"hdb", GenScheme("hdb"), 0, false, []string{"sa", "saphana", "sap", "hana"}, ""},
		{"n1ql", GenFromURL("http://localhost:9000/"), 0, false, []string{"couchbase"}, ""},
		{"odbc", GenODBC, ProtoAny, false, nil, ""},
		{"oleodbc", GenOLEODBC, ProtoAny, false, []string{"oo", "ole"}, "adodb"},
		{"presto", GenScheme("http"), 0, false, []string{"prestodb"}, ""},
		{"ql", GenOpaque, 0, true, []string{"ql", "cznic", "cznicql"}, ""},
		{"sqlany", GenSybase, 0, false, []string{"sy", "sybase", "any"}, ""},
		{"voltdb", GenVoltDB, 0, false, []string{"volt", "vdb"}, ""},
	}
}

func init() {
	schemes := BaseSchemes()
	schemeMap = make(map[string]*Scheme, len(schemes))

	// register
	for _, scheme := range schemes {
		Register(scheme)
	}
}

// schemeMap is the map of registered schemes.
var schemeMap map[string]*Scheme

// registerAlias registers a alias for an already registered Scheme.
func registerAlias(name, alias string, doSort bool) {
	scheme, ok := schemeMap[name]
	if !ok {
		panic(fmt.Sprintf("scheme %s not registered", name))
	}

	if doSort && has(scheme.Aliases, alias) {
		panic(fmt.Sprintf("scheme %s already has alias %s", name, alias))
	}

	if _, ok := schemeMap[alias]; ok {
		panic(fmt.Sprintf("scheme %s already registered", alias))
	}

	scheme.Aliases = append(scheme.Aliases, alias)
	if doSort {
		sort.Sort(ss(scheme.Aliases))
	}

	schemeMap[alias] = scheme
}

// Register registers a Scheme.
func Register(scheme Scheme) {
	if scheme.Generator == nil {
		panic("must specify Generator when registering Scheme")
	}

	if scheme.Opaque && scheme.Proto&ProtoUnix != 0 {
		panic("scheme must support only Opaque or Unix protocols, not both")
	}

	// register
	if _, ok := schemeMap[scheme.Driver]; ok {
		panic(fmt.Sprintf("scheme %s already registered", scheme.Driver))
	}

	sz := &Scheme{
		Driver:    scheme.Driver,
		Generator: scheme.Generator,
		Proto:     scheme.Proto,
		Opaque:    scheme.Opaque,
		Override:  scheme.Override,
	}

	schemeMap[scheme.Driver] = sz

	// add aliases
	var hasShort bool
	for _, alias := range scheme.Aliases {
		if len(alias) == 2 {
			hasShort = true
		}
		if scheme.Driver != alias {
			registerAlias(scheme.Driver, alias, false)
		}
	}

	if !hasShort && len(scheme.Driver) > 2 {
		registerAlias(scheme.Driver, scheme.Driver[:2], false)
	}

	// ensure always at least one alias, and that if Driver is 2 characters,
	// that it gets added as well
	if len(sz.Aliases) == 0 || len(scheme.Driver) == 2 {
		sz.Aliases = append(sz.Aliases, scheme.Driver)
	}

	// sort
	sort.Sort(ss(sz.Aliases))
}

// Unregister unregisters a Scheme and all associated aliases.
func Unregister(name string) *Scheme {
	scheme, ok := schemeMap[name]
	if ok {
		for _, alias := range scheme.Aliases {
			delete(schemeMap, alias)
		}
		delete(schemeMap, name)
		return scheme
	}
	return nil
}

// RegisterAlias registers a alias for an already registered Scheme.h
func RegisterAlias(name, alias string) {
	registerAlias(name, alias, true)
}

// has is a util func to determine if a contains b.
func has(a []string, b string) bool {
	for _, s := range a {
		if s == b {
			return true
		}
	}

	return false
}

// SchemeDriverAndAliases returns the registered driver and aliases for a
// database scheme.
func SchemeDriverAndAliases(name string) (string, []string) {
	if scheme, ok := schemeMap[name]; ok {
		driver := scheme.Driver
		if scheme.Override != "" {
			driver = scheme.Override
		}

		var aliases []string
		for _, alias := range scheme.Aliases {
			if alias == driver {
				continue
			}
			aliases = append(aliases, alias)
		}

		sort.Sort(ss(aliases))

		return driver, aliases
	}

	return "", nil
}

// ss is a util type to provide sorting of a string slice (used for sorting
// aliases).
type ss []string

func (s ss) Len() int      { return len(s) }
func (s ss) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s ss) Less(i, j int) bool {
	if len(s[i]) <= len(s[j]) {
		return true
	}

	if len(s[j]) < len(s[i]) {
		return false
	}

	return s[i] < s[j]
}
<|endoftext|>


<commit_before>/*
Copyright 2014 The Kubernetes Authors All rights reserved.

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 util

import (
	"fmt"
	"io"
	"strings"

	"k8s.io/kubernetes/pkg/api/meta"
	"k8s.io/kubernetes/pkg/kubectl"

	"github.com/spf13/cobra"
)

// AddPrinterFlags adds printing related flags to a command (e.g. output format, no headers, template path)
func AddPrinterFlags(cmd *cobra.Command) {
	cmd.Flags().StringP("output", "o", "", "Output format. One of: json|yaml|wide|name|go-template=...|go-template-file=...|jsonpath=...|jsonpath-file=... See golang template [http://golang.org/pkg/text/template/#pkg-overview] and jsonpath template [http://releases.k8s.io/HEAD/docs/user-guide/jsonpath.md].")
	cmd.Flags().String("output-version", "", "Output the formatted object with the given version (default api-version).")
	cmd.Flags().Bool("no-headers", false, "When using the default output, don't print headers.")
	// template shorthand -t is deprecated to support -t for --tty
	// TODO: remove template flag shorthand -t
	cmd.Flags().StringP("template", "t", "", "Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].")
	cmd.Flags().MarkShorthandDeprecated("template", "please use --template instead")
	cmd.Flags().String("sort-by", "", "If non-empty, sort list types using this field specification.  The field specification is expressed as a JSONPath expression (e.g. 'ObjectMeta.Name'). The field in the API resource specified by this JSONPath expression must be an integer or a string.")
	cmd.Flags().BoolP("show-all", "a", false, "When printing, show all resources (default hide terminated pods.)")
}

// AddOutputFlagsForMutation adds output related flags to a command. Used by mutations only.
func AddOutputFlagsForMutation(cmd *cobra.Command) {
	cmd.Flags().StringP("output", "o", "", "Output mode. Use \"-o name\" for shorter output (resource/name).")
}

// PrintSuccess prints message after finishing mutating operations
func PrintSuccess(mapper meta.RESTMapper, shortOutput bool, out io.Writer, resource string, name string, operation string) {
	resource, _ = mapper.ResourceSingularizer(resource)
	if shortOutput {
		// -o name: prints resource/name
		if len(resource) > 0 {
			fmt.Fprintf(out, "%s/%s\n", resource, name)
		} else {
			fmt.Fprintf(out, "%s\n", name)
		}
	} else {
		// understandable output by default
		if len(resource) > 0 {
			fmt.Fprintf(out, "%s \"%s\" %s\n", resource, name, operation)
		} else {
			fmt.Fprintf(out, "\"%s\" %s\n", name, operation)
		}
	}
}

// ValidateOutputArgs validates -o flag args for mutations
func ValidateOutputArgs(cmd *cobra.Command) error {
	outputMode := GetFlagString(cmd, "output")
	if outputMode != "" && outputMode != "name" {
		return UsageError(cmd, "Unexpected -o output mode: %v. We only support '-o name'.", outputMode)
	}
	return nil
}

// OutputVersion returns the preferred output version for generic content (JSON, YAML, or templates)
func OutputVersion(cmd *cobra.Command, defaultVersion string) string {
	outputVersion := GetFlagString(cmd, "output-version")
	if len(outputVersion) == 0 {
		outputVersion = defaultVersion
	}
	return outputVersion
}

// PrinterForCommand returns the default printer for this command.
// Requires that printer flags have been added to cmd (see AddPrinterFlags).
func PrinterForCommand(cmd *cobra.Command) (kubectl.ResourcePrinter, bool, error) {
	outputFormat := GetFlagString(cmd, "output")

	// templates are logically optional for specifying a format.
	// TODO once https://github.com/kubernetes/kubernetes/issues/12668 is fixed, this should fall back to GetFlagString
	templateFile, _ := cmd.Flags().GetString("template")
	if len(outputFormat) == 0 && len(templateFile) != 0 {
		outputFormat = "template"
	}

	templateFormat := []string{"go-template=", "go-template-file=", "jsonpath=", "jsonpath-file="}
	for _, format := range templateFormat {
		if strings.HasPrefix(outputFormat, format) {
			templateFile = outputFormat[len(format):]
			outputFormat = format[:len(format)-1]
		}
	}

	printer, generic, err := kubectl.GetPrinter(outputFormat, templateFile)
	if err != nil {
		return nil, generic, err
	}

	return maybeWrapSortingPrinter(cmd, printer), generic, nil
}

func maybeWrapSortingPrinter(cmd *cobra.Command, printer kubectl.ResourcePrinter) kubectl.ResourcePrinter {
	sorting := GetFlagString(cmd, "sort-by")
	if len(sorting) != 0 {
		return &kubectl.SortingPrinter{
			Delegate:  printer,
			SortField: fmt.Sprintf("{%s}", sorting),
		}
	}
	return printer
}
<commit_msg>UPSTREAM: 14502: don't fatal on missing sorting flag<commit_after>/*
Copyright 2014 The Kubernetes Authors All rights reserved.

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 util

import (
	"fmt"
	"io"
	"strings"

	"k8s.io/kubernetes/pkg/api/meta"
	"k8s.io/kubernetes/pkg/kubectl"

	"github.com/spf13/cobra"
)

// AddPrinterFlags adds printing related flags to a command (e.g. output format, no headers, template path)
func AddPrinterFlags(cmd *cobra.Command) {
	cmd.Flags().StringP("output", "o", "", "Output format. One of: json|yaml|wide|name|go-template=...|go-template-file=...|jsonpath=...|jsonpath-file=... See golang template [http://golang.org/pkg/text/template/#pkg-overview] and jsonpath template [http://releases.k8s.io/HEAD/docs/user-guide/jsonpath.md].")
	cmd.Flags().String("output-version", "", "Output the formatted object with the given version (default api-version).")
	cmd.Flags().Bool("no-headers", false, "When using the default output, don't print headers.")
	// template shorthand -t is deprecated to support -t for --tty
	// TODO: remove template flag shorthand -t
	cmd.Flags().StringP("template", "t", "", "Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].")
	cmd.Flags().MarkShorthandDeprecated("template", "please use --template instead")
	cmd.Flags().String("sort-by", "", "If non-empty, sort list types using this field specification.  The field specification is expressed as a JSONPath expression (e.g. 'ObjectMeta.Name'). The field in the API resource specified by this JSONPath expression must be an integer or a string.")
	cmd.Flags().BoolP("show-all", "a", false, "When printing, show all resources (default hide terminated pods.)")
}

// AddOutputFlagsForMutation adds output related flags to a command. Used by mutations only.
func AddOutputFlagsForMutation(cmd *cobra.Command) {
	cmd.Flags().StringP("output", "o", "", "Output mode. Use \"-o name\" for shorter output (resource/name).")
}

// PrintSuccess prints message after finishing mutating operations
func PrintSuccess(mapper meta.RESTMapper, shortOutput bool, out io.Writer, resource string, name string, operation string) {
	resource, _ = mapper.ResourceSingularizer(resource)
	if shortOutput {
		// -o name: prints resource/name
		if len(resource) > 0 {
			fmt.Fprintf(out, "%s/%s\n", resource, name)
		} else {
			fmt.Fprintf(out, "%s\n", name)
		}
	} else {
		// understandable output by default
		if len(resource) > 0 {
			fmt.Fprintf(out, "%s \"%s\" %s\n", resource, name, operation)
		} else {
			fmt.Fprintf(out, "\"%s\" %s\n", name, operation)
		}
	}
}

// ValidateOutputArgs validates -o flag args for mutations
func ValidateOutputArgs(cmd *cobra.Command) error {
	outputMode := GetFlagString(cmd, "output")
	if outputMode != "" && outputMode != "name" {
		return UsageError(cmd, "Unexpected -o output mode: %v. We only support '-o name'.", outputMode)
	}
	return nil
}

// OutputVersion returns the preferred output version for generic content (JSON, YAML, or templates)
func OutputVersion(cmd *cobra.Command, defaultVersion string) string {
	outputVersion := GetFlagString(cmd, "output-version")
	if len(outputVersion) == 0 {
		outputVersion = defaultVersion
	}
	return outputVersion
}

// PrinterForCommand returns the default printer for this command.
// Requires that printer flags have been added to cmd (see AddPrinterFlags).
func PrinterForCommand(cmd *cobra.Command) (kubectl.ResourcePrinter, bool, error) {
	outputFormat := GetFlagString(cmd, "output")

	// templates are logically optional for specifying a format.
	// TODO once https://github.com/kubernetes/kubernetes/issues/12668 is fixed, this should fall back to GetFlagString
	templateFile, _ := cmd.Flags().GetString("template")
	if len(outputFormat) == 0 && len(templateFile) != 0 {
		outputFormat = "template"
	}

	templateFormat := []string{"go-template=", "go-template-file=", "jsonpath=", "jsonpath-file="}
	for _, format := range templateFormat {
		if strings.HasPrefix(outputFormat, format) {
			templateFile = outputFormat[len(format):]
			outputFormat = format[:len(format)-1]
		}
	}

	printer, generic, err := kubectl.GetPrinter(outputFormat, templateFile)
	if err != nil {
		return nil, generic, err
	}

	return maybeWrapSortingPrinter(cmd, printer), generic, nil
}

func maybeWrapSortingPrinter(cmd *cobra.Command, printer kubectl.ResourcePrinter) kubectl.ResourcePrinter {
	sorting, err := cmd.Flags().GetString("sort-by")
	if err != nil {
		// error can happen on missing flag or bad flag type.  In either case, this command didn't intent to sort
		return printer
	}

	if len(sorting) != 0 {
		return &kubectl.SortingPrinter{
			Delegate:  printer,
			SortField: fmt.Sprintf("{%s}", sorting),
		}
	}
	return printer
}
<|endoftext|>