<commit_before>// Package goawk is an implementation of AWK written in Go.
//
// You can use the command-line "goawk" command or run AWK from your
// Go programs using the "interp" package. The command-line program
// has the same interface as regular awk:
//
//     goawk [-F fs] [-v var=value] [-f progfile | 'prog'] [file ...]
//
// The -F flag specifies the field separator (the default is to split
// on whitespace). The -v flag allows you to set a variable to a
// given value (multiple -v flags allowed). The -f flag allows you to
// read AWK source from a file instead of the 'prog' command-line
// argument. The rest of the arguments are input filenames (default
// is to read from stdin).
//
// A simple example (prints the sum of the numbers in the file's
// second column):
//
//     $ echo 'foo 12
//     > bar 34
//     > baz 56' >file.txt
//     $ goawk '{ sum += $2 } END { print sum }' file.txt
//     102
//
// To use GoAWK in your Go programs, see README.md or the "interp"
// docs.
//
package main

import (
	"bytes"
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"runtime/pprof"
	"strings"
	"unicode/utf8"

	"github.com/benhoyt/goawk/interp"
	"github.com/benhoyt/goawk/lexer"
	"github.com/benhoyt/goawk/parser"
)

const (
	version    = "v1.6.0"
	copyright  = "GoAWK " + version + " - Copyright (c) 2019 Ben Hoyt"
	shortUsage = "usage: goawk [-F fs] [-v var=value] [-f progfile | 'prog'] [file ...]"
	longUsage  = `Standard AWK arguments:
  -F separator
        field separator (default " ")
  -v assignment
        name=value variable assignment (multiple allowed)
  -f progfile
        load AWK source from progfile (multiple allowed)

Additional GoAWK arguments:
  -cpuprofile file
        write CPU profile to file
  -d    debug mode (print parsed AST to stderr)
  -dt   show variable types debug info
  -h    show this usage message
  -version
        show GoAWK version and exit
`
)

func main() {
	// Parse command line arguments manually rather than using the
	// "flag" package so we can support flags with no space between
	// flag and argument, like '-F:' (allowed by POSIX)
	args := make([]string, 0)
	fieldSep := " "
	progFiles := make([]string, 0)
	vars := make([]string, 0)
	cpuprofile := ""
	debug := false
	debugTypes := false
	memprofile := ""
	for i := 1; i < len(os.Args); i++ {
		switch os.Args[i] {
		case "-F":
			if i+1 >= len(os.Args) {
				errorExit("flag needs an argument: -F")
			}
			i++
			fieldSep = os.Args[i]
		case "-f":
			if i+1 >= len(os.Args) {
				errorExit("flag needs an argument: -f")
			}
			i++
			progFiles = append(progFiles, os.Args[i])
		case "-v":
			if i+1 >= len(os.Args) {
				errorExit("flag needs an argument: -v")
			}
			i++
			vars = append(vars, os.Args[i])
		case "-cpuprofile":
			if i+1 >= len(os.Args) {
				errorExit("flag needs an argument: -cpuprofile")
			}
			i++
			cpuprofile = os.Args[i]
		case "-d":
			debug = true
		case "-dt":
			debugTypes = true
		case "-h", "--help":
			fmt.Printf("%s\n\n%s\n\n%s", copyright, shortUsage, longUsage)
			os.Exit(0)
		case "-memprofile":
			if i+1 >= len(os.Args) {
				errorExit("flag needs an argument: -memprofile")
			}
			i++
			memprofile = os.Args[i]
		case "-version", "--version":
			fmt.Println(version)
			os.Exit(0)
		default:
			arg := os.Args[i]
			switch {
			case strings.HasPrefix(arg, "-F"):
				fieldSep = arg[2:]
			case strings.HasPrefix(arg, "-f"):
				progFiles = append(progFiles, arg[2:])
			case strings.HasPrefix(arg, "-v"):
				vars = append(vars, arg[2:])
			case strings.HasPrefix(arg, "-cpuprofile="):
				cpuprofile = arg[12:]
			case strings.HasPrefix(arg, "-memprofile="):
				memprofile = arg[12:]
			case len(arg) > 1 && arg[0] == '-':
				errorExit("flag provided but not defined: %s", arg)
			default:
				args = append(args, arg)
			}
		}
	}

	var src []byte
	if len(progFiles) > 0 {
		// Read source: the concatenation of all source files specified
		buf := &bytes.Buffer{}
		for _, progFile := range progFiles {
			if progFile == "-" {
				_, err := buf.ReadFrom(os.Stdin)
				if err != nil {
					errorExit("%s", err)
				}
			} else {
				f, err := os.Open(progFile)
				if err != nil {
					errorExit("%s", err)
				}
				_, err = buf.ReadFrom(f)
				if err != nil {
					f.Close()
					errorExit("%s", err)
				}
				f.Close()
			}
			// Append newline to file in case it doesn't end with one
			buf.WriteByte('\n')
		}
		src = buf.Bytes()
	} else {
		if len(args) < 1 {
			errorExit(shortUsage)
		}
		src = []byte(args[0])
		args = args[1:]
	}

	// Parse source code and setup interpreter
	parserConfig := &parser.ParserConfig{
		DebugTypes:  debugTypes,
		DebugWriter: os.Stderr,
	}
	prog, err := parser.ParseProgram(src, parserConfig)
	if err != nil {
		errMsg := fmt.Sprintf("%s", err)
		if err, ok := err.(*parser.ParseError); ok {
			showSourceLine(src, err.Position, len(errMsg))
		}
		errorExit("%s", errMsg)
	}
	if debug {
		fmt.Fprintln(os.Stderr, prog)
	}
	config := &interp.Config{
		Argv0: filepath.Base(os.Args[0]),
		Args:  args,
		Vars:  []string{"FS", fieldSep},
	}
	for _, v := range vars {
		parts := strings.SplitN(v, "=", 2)
		if len(parts) != 2 {
			errorExit("-v flag must be in format name=value")
		}
		config.Vars = append(config.Vars, parts[0], parts[1])
	}

	if cpuprofile != "" {
		f, err := os.Create(cpuprofile)
		if err != nil {
			errorExit("could not create CPU profile: %v", err)
		}
		if err := pprof.StartCPUProfile(f); err != nil {
			errorExit("could not start CPU profile: %v", err)
		}
	}

	status, err := interp.ExecProgram(prog, config)
	if err != nil {
		errorExit("%s", err)
	}

	if cpuprofile != "" {
		pprof.StopCPUProfile()
	}

	if memprofile != "" {
		f, err := os.Create(memprofile)
		if err != nil {
			errorExit("could not create memory profile: %v", err)
		}
		runtime.GC() // get up-to-date statistics
		if err := pprof.WriteHeapProfile(f); err != nil {
			errorExit("could not write memory profile: %v", err)
		}
		f.Close()
	}

	os.Exit(status)
}

// For parse errors, show source line and position of error, eg:
//
// -----------------------------------------------------
// BEGIN { x*; }
//           ^
// -----------------------------------------------------
// parse error at 1:11: expected expression instead of ;
//
func showSourceLine(src []byte, pos lexer.Position, dividerLen int) {
	divider := strings.Repeat("-", dividerLen)
	if divider != "" {
		fmt.Fprintln(os.Stderr, divider)
	}
	lines := bytes.Split(src, []byte{'\n'})
	srcLine := string(lines[pos.Line-1])
	numTabs := strings.Count(srcLine[:pos.Column-1], "\t")
	runeColumn := utf8.RuneCountInString(srcLine[:pos.Column-1])
	fmt.Fprintln(os.Stderr, strings.Replace(srcLine, "\t", "    ", -1))
	fmt.Fprintln(os.Stderr, strings.Repeat(" ", runeColumn)+strings.Repeat("   ", numTabs)+"^")
	if divider != "" {
		fmt.Fprintln(os.Stderr, divider)
	}
}

func errorExit(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, format+"\n", args...)
	os.Exit(1)
}

// Helper type for flag parsing to allow multiple -f and -v arguments
type multiString []string

func (m *multiString) String() string {
	return fmt.Sprintf("%v", []string(*m))
}

func (m *multiString) Set(value string) error {
	*m = append(*m, value)
	return nil
}
<commit_msg>Remove now-unused multiString type<commit_after>// Package goawk is an implementation of AWK written in Go.
//
// You can use the command-line "goawk" command or run AWK from your
// Go programs using the "interp" package. The command-line program
// has the same interface as regular awk:
//
//     goawk [-F fs] [-v var=value] [-f progfile | 'prog'] [file ...]
//
// The -F flag specifies the field separator (the default is to split
// on whitespace). The -v flag allows you to set a variable to a
// given value (multiple -v flags allowed). The -f flag allows you to
// read AWK source from a file instead of the 'prog' command-line
// argument. The rest of the arguments are input filenames (default
// is to read from stdin).
//
// A simple example (prints the sum of the numbers in the file's
// second column):
//
//     $ echo 'foo 12
//     > bar 34
//     > baz 56' >file.txt
//     $ goawk '{ sum += $2 } END { print sum }' file.txt
//     102
//
// To use GoAWK in your Go programs, see README.md or the "interp"
// docs.
//
package main

import (
	"bytes"
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"runtime/pprof"
	"strings"
	"unicode/utf8"

	"github.com/benhoyt/goawk/interp"
	"github.com/benhoyt/goawk/lexer"
	"github.com/benhoyt/goawk/parser"
)

const (
	version    = "v1.6.0"
	copyright  = "GoAWK " + version + " - Copyright (c) 2019 Ben Hoyt"
	shortUsage = "usage: goawk [-F fs] [-v var=value] [-f progfile | 'prog'] [file ...]"
	longUsage  = `Standard AWK arguments:
  -F separator
        field separator (default " ")
  -v assignment
        name=value variable assignment (multiple allowed)
  -f progfile
        load AWK source from progfile (multiple allowed)

Additional GoAWK arguments:
  -cpuprofile file
        write CPU profile to file
  -d    debug mode (print parsed AST to stderr)
  -dt   show variable types debug info
  -h    show this usage message
  -version
        show GoAWK version and exit
`
)

func main() {
	// Parse command line arguments manually rather than using the
	// "flag" package so we can support flags with no space between
	// flag and argument, like '-F:' (allowed by POSIX)
	args := make([]string, 0)
	fieldSep := " "
	progFiles := make([]string, 0)
	vars := make([]string, 0)
	cpuprofile := ""
	debug := false
	debugTypes := false
	memprofile := ""
	for i := 1; i < len(os.Args); i++ {
		switch os.Args[i] {
		case "-F":
			if i+1 >= len(os.Args) {
				errorExit("flag needs an argument: -F")
			}
			i++
			fieldSep = os.Args[i]
		case "-f":
			if i+1 >= len(os.Args) {
				errorExit("flag needs an argument: -f")
			}
			i++
			progFiles = append(progFiles, os.Args[i])
		case "-v":
			if i+1 >= len(os.Args) {
				errorExit("flag needs an argument: -v")
			}
			i++
			vars = append(vars, os.Args[i])
		case "-cpuprofile":
			if i+1 >= len(os.Args) {
				errorExit("flag needs an argument: -cpuprofile")
			}
			i++
			cpuprofile = os.Args[i]
		case "-d":
			debug = true
		case "-dt":
			debugTypes = true
		case "-h", "--help":
			fmt.Printf("%s\n\n%s\n\n%s", copyright, shortUsage, longUsage)
			os.Exit(0)
		case "-memprofile":
			if i+1 >= len(os.Args) {
				errorExit("flag needs an argument: -memprofile")
			}
			i++
			memprofile = os.Args[i]
		case "-version", "--version":
			fmt.Println(version)
			os.Exit(0)
		default:
			arg := os.Args[i]
			switch {
			case strings.HasPrefix(arg, "-F"):
				fieldSep = arg[2:]
			case strings.HasPrefix(arg, "-f"):
				progFiles = append(progFiles, arg[2:])
			case strings.HasPrefix(arg, "-v"):
				vars = append(vars, arg[2:])
			case strings.HasPrefix(arg, "-cpuprofile="):
				cpuprofile = arg[12:]
			case strings.HasPrefix(arg, "-memprofile="):
				memprofile = arg[12:]
			case len(arg) > 1 && arg[0] == '-':
				errorExit("flag provided but not defined: %s", arg)
			default:
				args = append(args, arg)
			}
		}
	}

	var src []byte
	if len(progFiles) > 0 {
		// Read source: the concatenation of all source files specified
		buf := &bytes.Buffer{}
		for _, progFile := range progFiles {
			if progFile == "-" {
				_, err := buf.ReadFrom(os.Stdin)
				if err != nil {
					errorExit("%s", err)
				}
			} else {
				f, err := os.Open(progFile)
				if err != nil {
					errorExit("%s", err)
				}
				_, err = buf.ReadFrom(f)
				if err != nil {
					f.Close()
					errorExit("%s", err)
				}
				f.Close()
			}
			// Append newline to file in case it doesn't end with one
			buf.WriteByte('\n')
		}
		src = buf.Bytes()
	} else {
		if len(args) < 1 {
			errorExit(shortUsage)
		}
		src = []byte(args[0])
		args = args[1:]
	}

	// Parse source code and setup interpreter
	parserConfig := &parser.ParserConfig{
		DebugTypes:  debugTypes,
		DebugWriter: os.Stderr,
	}
	prog, err := parser.ParseProgram(src, parserConfig)
	if err != nil {
		errMsg := fmt.Sprintf("%s", err)
		if err, ok := err.(*parser.ParseError); ok {
			showSourceLine(src, err.Position, len(errMsg))
		}
		errorExit("%s", errMsg)
	}
	if debug {
		fmt.Fprintln(os.Stderr, prog)
	}
	config := &interp.Config{
		Argv0: filepath.Base(os.Args[0]),
		Args:  args,
		Vars:  []string{"FS", fieldSep},
	}
	for _, v := range vars {
		parts := strings.SplitN(v, "=", 2)
		if len(parts) != 2 {
			errorExit("-v flag must be in format name=value")
		}
		config.Vars = append(config.Vars, parts[0], parts[1])
	}

	if cpuprofile != "" {
		f, err := os.Create(cpuprofile)
		if err != nil {
			errorExit("could not create CPU profile: %v", err)
		}
		if err := pprof.StartCPUProfile(f); err != nil {
			errorExit("could not start CPU profile: %v", err)
		}
	}

	status, err := interp.ExecProgram(prog, config)
	if err != nil {
		errorExit("%s", err)
	}

	if cpuprofile != "" {
		pprof.StopCPUProfile()
	}

	if memprofile != "" {
		f, err := os.Create(memprofile)
		if err != nil {
			errorExit("could not create memory profile: %v", err)
		}
		runtime.GC() // get up-to-date statistics
		if err := pprof.WriteHeapProfile(f); err != nil {
			errorExit("could not write memory profile: %v", err)
		}
		f.Close()
	}

	os.Exit(status)
}

// For parse errors, show source line and position of error, eg:
//
// -----------------------------------------------------
// BEGIN { x*; }
//           ^
// -----------------------------------------------------
// parse error at 1:11: expected expression instead of ;
//
func showSourceLine(src []byte, pos lexer.Position, dividerLen int) {
	divider := strings.Repeat("-", dividerLen)
	if divider != "" {
		fmt.Fprintln(os.Stderr, divider)
	}
	lines := bytes.Split(src, []byte{'\n'})
	srcLine := string(lines[pos.Line-1])
	numTabs := strings.Count(srcLine[:pos.Column-1], "\t")
	runeColumn := utf8.RuneCountInString(srcLine[:pos.Column-1])
	fmt.Fprintln(os.Stderr, strings.Replace(srcLine, "\t", "    ", -1))
	fmt.Fprintln(os.Stderr, strings.Repeat(" ", runeColumn)+strings.Repeat("   ", numTabs)+"^")
	if divider != "" {
		fmt.Fprintln(os.Stderr, divider)
	}
}

func errorExit(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, format+"\n", args...)
	os.Exit(1)
}
<|endoftext|>


<commit_before>package gockl

import (
	"io"
	"strings"
)

type Token interface {
	Raw() string
}

type ElementToken interface {
	Name() string
}

type TextToken string

func (t TextToken) Raw() string {
	return string(t)
}

type CharDataToken string

func (t CharDataToken) Raw() string {
	return string(t)
}

type CommentToken string

func (t CommentToken) Raw() string {
	return string(t)
}

type DirectiveToken string

func (t DirectiveToken) Raw() string {
	return string(t)
}

type ProcInstToken string

func (t ProcInstToken) Raw() string {
	return string(t)
}

type StartElementToken string

func (t StartElementToken) Raw() string {
	return string(t)
}

func (t StartElementToken) Name() string {
	if idx := strings.IndexAny(string(t)[1:], " \t\r\n>/"); idx > -1 {
		return string(t)[1 : 1+idx]
	}
	return string(t)[1:]
}

type EndElementToken string

func (t EndElementToken) Raw() string {
	return string(t)
}

func (t EndElementToken) Name() string {
	return string(t)[2 : len(t)-1]
}

type StartEndElementToken string

func (t StartEndElementToken) Raw() string {
	return string(t)
}

type Tokenizer struct {
	Input    string
	Position int
}

func New(input string) *Tokenizer {
	return &Tokenizer{
		Input: strings.Replace(input, "\r\n", "\n", -1),
	}
}

func (me *Tokenizer) shift(end string) string {
	if pos := strings.Index(me.Input[me.Position:], end); pos > -1 {
		r := me.Input[me.Position : me.Position+pos+len(end)]
		me.Position += pos + len(end)
		return r
	}

	return me.shiftUntil("<")
}

func (me *Tokenizer) shiftUntil(next string) string {
	if pos := strings.Index(me.Input[me.Position:], next); pos > -1 {
		r := me.Input[me.Position : me.Position+pos]
		me.Position += pos
		return r
	}

	r := me.Input[me.Position:]
	me.Position = len(me.Input)
	return r
}

func (me *Tokenizer) Next() (Token, error) {
	if me.Position >= len(me.Input) {
		return nil, io.EOF
	}

	if me.Position >= len(me.Input)-3 {
		goto dunno
	}

	switch me.Input[me.Position] {
	case '<':
		switch me.Input[me.Position+1] {
		case '?':
			return ProcInstToken(me.shift("?>")), nil
		case '!':
			if me.Input[me.Position+2:me.Position+4] != "--" {
				goto dunno
			}
			return CommentToken(me.shift("-->")), nil
		case '/':
			return EndElementToken(me.shift(">")), nil
		default:
			raw := me.shift(">")

			if raw[len(raw)-2] == '/' {
				return StartEndElementToken(raw), nil
			}

			return StartElementToken(raw), nil
		}
	}

dunno:

	return TextToken(me.shiftUntil("<")), nil
}
<commit_msg>Don't convert newlines.<commit_after>package gockl

import (
	"io"
	"strings"
)

type Token interface {
	Raw() string
}

type ElementToken interface {
	Name() string
}

type TextToken string

func (t TextToken) Raw() string {
	return string(t)
}

type CharDataToken string

func (t CharDataToken) Raw() string {
	return string(t)
}

type CommentToken string

func (t CommentToken) Raw() string {
	return string(t)
}

type DirectiveToken string

func (t DirectiveToken) Raw() string {
	return string(t)
}

type ProcInstToken string

func (t ProcInstToken) Raw() string {
	return string(t)
}

type StartElementToken string

func (t StartElementToken) Raw() string {
	return string(t)
}

func (t StartElementToken) Name() string {
	if idx := strings.IndexAny(string(t)[1:], " \t\r\n>/"); idx > -1 {
		return string(t)[1 : 1+idx]
	}
	return string(t)[1:]
}

type EndElementToken string

func (t EndElementToken) Raw() string {
	return string(t)
}

func (t EndElementToken) Name() string {
	return string(t)[2 : len(t)-1]
}

type StartEndElementToken string

func (t StartEndElementToken) Raw() string {
	return string(t)
}

type Tokenizer struct {
	Input    string
	Position int
}

func New(input string) *Tokenizer {
	return &Tokenizer{Input: input}
}

func (me *Tokenizer) shift(end string) string {
	if pos := strings.Index(me.Input[me.Position:], end); pos > -1 {
		r := me.Input[me.Position : me.Position+pos+len(end)]
		me.Position += pos + len(end)
		return r
	}

	return me.shiftUntil("<")
}

func (me *Tokenizer) shiftUntil(next string) string {
	if pos := strings.Index(me.Input[me.Position:], next); pos > -1 {
		r := me.Input[me.Position : me.Position+pos]
		me.Position += pos
		return r
	}

	r := me.Input[me.Position:]
	me.Position = len(me.Input)
	return r
}

func (me *Tokenizer) Next() (Token, error) {
	if me.Position >= len(me.Input) {
		return nil, io.EOF
	}

	if me.Position >= len(me.Input)-3 {
		goto dunno
	}

	switch me.Input[me.Position] {
	case '<':
		switch me.Input[me.Position+1] {
		case '?':
			return ProcInstToken(me.shift("?>")), nil
		case '!':
			if me.Input[me.Position+2:me.Position+4] != "--" {
				goto dunno
			}
			return CommentToken(me.shift("-->")), nil
		case '/':
			return EndElementToken(me.shift(">")), nil
		default:
			raw := me.shift(">")

			if raw[len(raw)-2] == '/' {
				return StartEndElementToken(raw), nil
			}

			return StartElementToken(raw), nil
		}
	}

dunno:

	return TextToken(me.shiftUntil("<")), nil
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Knative Authors

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

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

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

package slack

import (
	"os"
	"testing"
	"time"

	"knative.dev/pkg/test/mako/config"
	"knative.dev/pkg/test/slackutil/fakeslackutil"
)

var mh MessageHandler

func TestMain(m *testing.M) {
	client := fakeslackutil.NewFakeSlackClient()
	mh = MessageHandler{
		readClient:  client,
		writeClient: client,
		channels: []config.Channel{
			{Name: "test_channel1", Identity: "fsfdsf"},
			{Name: "test_channel2", Identity: "fdsfhfdh"},
		},
		dryrun: false,
	}
	os.Exit(m.Run())
}

func TestMessaging(t *testing.T) {
	testCases := []struct {
		name           string
	}{
		{"test name"},
		{"special name <>&'\""},
	}

	for _, tc := range testCases {
		historySizes := make([]int, len(mh.channels))
		for i, channel := range mh.channels {
			initHistory, err := mh.readClient.MessageHistory(channel.Identity, time.Now().Add(-1*time.Hour))
			if err != nil {
				t.Fatalf("expected to get the message history, but failed: %v", err)
			}
			historySizes[i] = len(initHistory)
		}

		firstMsg := "first message"
		if err := mh.SendAlert(tc.name, firstMsg); err != nil {
			t.Fatalf("expected to send the message, but failed: %v", err)
		}
		for i, channel := range mh.channels {
			history, err := mh.readClient.MessageHistory(channel.Identity, time.Now().Add(-1*time.Hour))
			if err != nil {
				t.Fatalf("expected to get the message history, but failed: %v", err)
			}
			if len(history) != historySizes[i] + 1 {
				t.Fatalf("the message is expected to be successfully sent, but failed: %v", err)
			}
		}

		secondMsg := "second message"
		if err := mh.SendAlert(tc.name, secondMsg); err != nil {
			t.Fatalf("expected to send the message, but failed: %v", err)
		}
		for i, channel := range mh.channels {
			history, err := mh.readClient.MessageHistory(channel.Identity, time.Now().Add(-1*time.Hour))
			if err != nil {
				t.Fatalf("expected to get the message history, but failed: %v", err)
			}
			if len(history) != historySizes[i] + 1 {
				t.Fatalf("the message history is expected to be unchanged, but now it's: %d", len(history))
			}
		}
	}
}

func TestDecoratedName(t *testing.T) {
	testCases := []struct {
		name           string
		expectedResult string
	}{
		{"demo test1", "[demo test1]"},
		{"[demo test2]", "[[demo test2]]"},
	}
	for _, tc := range testCases {
		actualResult := decoratedName(tc.name)
		if tc.expectedResult != actualResult {
			t.Fatalf("expected to get %q for decoratedName(%s), but got %q", tc.expectedResult, tc.name, actualResult)
		}
	}
}
<commit_msg>golang format tools (#1016)<commit_after>/*
Copyright 2019 The Knative Authors

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

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

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

package slack

import (
	"os"
	"testing"
	"time"

	"knative.dev/pkg/test/mako/config"
	"knative.dev/pkg/test/slackutil/fakeslackutil"
)

var mh MessageHandler

func TestMain(m *testing.M) {
	client := fakeslackutil.NewFakeSlackClient()
	mh = MessageHandler{
		readClient:  client,
		writeClient: client,
		channels: []config.Channel{
			{Name: "test_channel1", Identity: "fsfdsf"},
			{Name: "test_channel2", Identity: "fdsfhfdh"},
		},
		dryrun: false,
	}
	os.Exit(m.Run())
}

func TestMessaging(t *testing.T) {
	testCases := []struct {
		name string
	}{
		{"test name"},
		{"special name <>&'\""},
	}

	for _, tc := range testCases {
		historySizes := make([]int, len(mh.channels))
		for i, channel := range mh.channels {
			initHistory, err := mh.readClient.MessageHistory(channel.Identity, time.Now().Add(-1*time.Hour))
			if err != nil {
				t.Fatalf("expected to get the message history, but failed: %v", err)
			}
			historySizes[i] = len(initHistory)
		}

		firstMsg := "first message"
		if err := mh.SendAlert(tc.name, firstMsg); err != nil {
			t.Fatalf("expected to send the message, but failed: %v", err)
		}
		for i, channel := range mh.channels {
			history, err := mh.readClient.MessageHistory(channel.Identity, time.Now().Add(-1*time.Hour))
			if err != nil {
				t.Fatalf("expected to get the message history, but failed: %v", err)
			}
			if len(history) != historySizes[i]+1 {
				t.Fatalf("the message is expected to be successfully sent, but failed: %v", err)
			}
		}

		secondMsg := "second message"
		if err := mh.SendAlert(tc.name, secondMsg); err != nil {
			t.Fatalf("expected to send the message, but failed: %v", err)
		}
		for i, channel := range mh.channels {
			history, err := mh.readClient.MessageHistory(channel.Identity, time.Now().Add(-1*time.Hour))
			if err != nil {
				t.Fatalf("expected to get the message history, but failed: %v", err)
			}
			if len(history) != historySizes[i]+1 {
				t.Fatalf("the message history is expected to be unchanged, but now it's: %d", len(history))
			}
		}
	}
}

func TestDecoratedName(t *testing.T) {
	testCases := []struct {
		name           string
		expectedResult string
	}{
		{"demo test1", "[demo test1]"},
		{"[demo test2]", "[[demo test2]]"},
	}
	for _, tc := range testCases {
		actualResult := decoratedName(tc.name)
		if tc.expectedResult != actualResult {
			t.Fatalf("expected to get %q for decoratedName(%s), but got %q", tc.expectedResult, tc.name, actualResult)
		}
	}
}
<|endoftext|>


<commit_before>package golet

import (
	"bufio"
	"context"
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"os/signal"
	"runtime"
	"sync"
	"syscall"
	"time"

	"github.com/Code-Hex/golet/internal/port"
	colorable "github.com/mattn/go-colorable"
	"github.com/robfig/cron"
)

type color int

const (
	red color = iota // + 31
	green
	yellow
	blue
	magenta
	cyan

	colornum int = 5
)

// config is main struct.
// struct comments from http://search.cpan.org/dist/Proclet/lib/Proclet.pm
// Proclet is a great module!!
type config struct {
	interval   time.Duration // interval in seconds between spawning services unless a service exits abnormally.
	color      bool          // colored log.
	logger     io.Writer     // sets the output destination file. use stderr by default.
	logWorker  bool          // enable worker for format logs. If disabled this option, cannot use logger opt too.
	execNotice bool          // enable start and exec notice message like: `16:38:12 worker.1 | Start callback: worker``.

	services   []Service
	wg         sync.WaitGroup
	once       sync.Once
	cancel     func()
	ctx        *signalCtx
	serviceNum int
	tags       map[string]bool
	cron       *cron.Cron
}

var shell []string

func init() {
	if runtime.GOOS == "windows" {
		path, err := exec.LookPath("cmd")
		if err != nil {
			panic("Could not find `cmd` command")
		}
		shell = []string{path, "/c"}
	} else {
		path, err := exec.LookPath("bash")
		if err != nil {
			panic("Could not find `bash` command")
		}
		shell = []string{path, "-c"}
	}
}

// Runner interface have methods for configuration and to run services.
type Runner interface {
	SetInterval(time.Duration)
	EnableColor()
	SetLogger(io.Writer)
	DisableLogger()
	DisableExecNotice()
	Env(map[string]string) error
	Add(...Service) error
	Run() error
}

// for settings
// SetInterval can specify the interval at which the command is executed.
func (c *config) SetInterval(t time.Duration) { c.interval = t }

// EnableColor can output colored log.
func (c *config) EnableColor() { c.color = true }

// SetLogger can specify the io.Writer
// for example in https://github.com/lestrrat/go-file-rotatelogs
/*
      logf, _ := rotatelogs.New(
  	    "/path/to/access_log.%Y%m%d%H%M",
  	    rotatelogs.WithLinkName("/path/to/access_log"),
  	    rotatelogs.WithMaxAge(24 * time.Hour),
  	    rotatelogs.WithRotationTime(time.Hour),
      )

	  golet.New(context.Background()).SetLogger(logf)
*/
func (c *config) SetLogger(f io.Writer) { c.logger = f }

// DisableLogger is prevent to output log
func (c *config) DisableLogger() { c.logWorker = false }

// DisableExecNotice is disable execute notifications
func (c *config) DisableExecNotice() { c.execNotice = false }

// New to create struct of golet.
func New(c context.Context) Runner {
	ctx, cancel := context.WithCancel(c)
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, syscall.SIGHUP, syscall.SIGTERM, syscall.SIGINT)
	return &config{
		interval:   0,
		color:      false,
		logger:     colorable.NewColorableStderr(),
		logWorker:  true,
		execNotice: true,

		ctx: &signalCtx{
			parent:  ctx,
			sigchan: signals,
		},
		cancel: cancel,
		tags:   map[string]bool{},
		cron:   cron.New(),
	}
}

// Env can add temporary environment variables.
func (c *config) Env(envs map[string]string) error {
	for k := range envs {
		if e := os.Setenv(k, envs[k]); e != nil {
			return e
		}
	}
	return nil
}

// Add can add runnable services
func (c *config) Add(services ...Service) error {
	for _, service := range services {
		c.serviceNum++
		if service.Tag == "" {
			service.Tag = fmt.Sprintf("%d", c.serviceNum)
		}
		if service.Worker <= 0 {
			service.Worker = 1
		}
		if _, ok := c.tags[service.Tag]; ok {
			return errors.New("tag: " + service.Tag + " is already exists")
		}
		c.tags[service.Tag] = true

		n, err := port.GetPort()
		if err != nil {
			return err
		}

		service.tmpPort = n
		service.color = color(c.serviceNum%colornum + 32)

		c.services = append(c.services, service)
	}
	return nil
}

// Run just like the name.
func (c *config) Run() error {
	services := make(map[string]Service)

	order := make([]string, 0, c.calcCapacitySize())

	// Assign services.
	if err := c.assign(&order, services); err != nil {
		return err
	}
	chps := make(chan *os.Process, 1)
	go c.waitSignals(chps, len(order))

	// Invoke workers.
	for _, sid := range order {
		service := services[sid]
		if service.isExecute() {
			// Execute the command with cron or goroutine
			if service.isCron() {
				c.addCmd(service, chps)
			} else {
				c.wg.Add(1)
				go func() {
					defer func() {
						service.ctx.Close()
						c.wg.Done()
					}()
				PROCESS:
					for {
						// Notify you have executed the command
						if c.execNotice {
							service.Printf("Exec command: %s\n", service.Exec)
						}
						select {
						case <-c.ctx.Done():
							return
						default:
							// If golet is recieved signal or exit code is 0, golet do not restart process.
							if err := run(service.prepare(), chps); err != nil {
								if exiterr, ok := err.(*exec.ExitError); ok {
									// See https://stackoverflow.com/a/10385867
									if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
										if !status.Signaled() {
											continue PROCESS
										}
										return
									}
								}
							}
							return
						}
					}
				}()
			}
		}

		if service.isCode() {
			// Run callback with cron or goroutine
			if service.isCron() {
				c.addTask(service)
			} else {
				c.wg.Add(1)
				go func() {
					defer func() {
						service.ctx.Close()
						c.wg.Done()
					}()
					// If this callback is dead, we should restart it. (like a supervisor)
					// So, this loop for that.
				CALLBACK:
					for {
						// Notify you have run the callback
						if c.execNotice {
							service.Printf("Callback: %s\n", service.Tag)
						}
						select {
						case <-c.ctx.Done():
							return
						default:
							if err := service.Code(service.ctx); err != nil {
								service.Printf("%s\n", err.Error())
								continue CALLBACK
							}
							return
						}
					}
				}()
			}
		}
		// Enable log worker if logWorker is true.
		if c.logWorker && (service.Code != nil || service.Exec != "") {
			rd := service.reader
			go c.logging(bufio.NewScanner(rd), sid, service.color)
		}
		// When the task is cron, it does not cause wait time.
		if service.Every == "" {
			time.Sleep(c.interval)
		}
	}

	c.wait(chps)

	return nil
}

// Calculate of the number of workers.
func (c *config) calcCapacitySize() (cap int) {
	for _, service := range c.services {
		cap += service.Worker
	}
	return
}

// Assign the service ID.
// It also make `order` slice to keep key order of `map[string]Service`.
func (c *config) assign(order *[]string, services map[string]Service) error {
	for _, service := range c.services {
		worker := service.Worker
		for i := 1; i <= worker; i++ {
			s := service
			if err := s.createContext(c.ctx, i); err != nil {
				return err
			}
			sid := fmt.Sprintf("%s.%d", s.Tag, i)
			services[sid] = s
			*order = append(*order, sid)
		}
	}
	return nil
}

// Receive process ID to be executed. or
// It traps the signal relate to parent process. sends a signal to the received process ID.
func (c *config) waitSignals(chps <-chan *os.Process, cap int) {
	procs := make([]*os.Process, 0, cap)
Loop:
	for {
		select {
		case proc := <-chps:
			// Replace used process(nil) with the newly generated process.
			// This run to reduce the memory allocation frequency.
			for i, p := range procs {
				if p == nil {
					procs[i] = proc
					continue Loop
				}
			}
			// If using all processes, allocate newly.
			procs = append(procs, proc)
		case c.ctx.signal = <-c.ctx.sigchan:
			switch c.ctx.signal {
			case syscall.SIGTERM, syscall.SIGHUP:
				c.ctx.signal = syscall.SIGTERM
				sendSignal2Procs(syscall.SIGTERM, procs)
				c.ctx.notifySignal()
			case syscall.SIGINT:
				sendSignal2Procs(syscall.SIGINT, procs)
				c.ctx.notifySignal()
			}
		case <-c.ctx.Done():
			c.cron.Stop()
			return
		}
	}
}

// sendSignal2Procs can send signal and replace os.Process struct of the terminated process with nil
func sendSignal2Procs(sig syscall.Signal, procs []*os.Process) {
	for i, p := range procs {
		if p != nil {
			p.Signal(sig)
			// In case of error, the process has already finished.
			if _, err := p.Wait(); err != nil {
				procs[i] = nil
			}
		}
	}
}

// Execute the command and send its process ID.
func run(c *exec.Cmd, chps chan<- *os.Process) error {
	if err := c.Start(); err != nil {
		return err
	}
	chps <- c.Process
	return c.Wait()
}

// Add a task to execute the command to cron.
func (c *config) addCmd(s Service, chps chan<- *os.Process) {
	// Notify you have executed the command
	if c.execNotice {
		s.Printf("Exec command: %s\n", s.Exec)
	}
	c.cron.AddFunc(s.Every, func() {
		run(s.prepare(), chps)
	})
}

// Add a task to execute the code block to cron.
func (c *config) addTask(s Service) {
	// Notify you have run the callback
	if c.execNotice {
		s.Printf("Callback: %s\n", s.Tag)
	}
	c.cron.AddFunc(s.Every, func() {
		s.Code(s.ctx)
	})
}

// Wait services
func (c *config) wait(chps chan<- *os.Process) {
	c.cron.Start()
	c.wg.Wait()
	signal.Stop(c.ctx.sigchan)
}

// Logging
func (c *config) logging(sc *bufio.Scanner, sid string, clr color) {
	for sc.Scan() {
		hour, min, sec := time.Now().Clock()
		if c.color {
			fmt.Fprintf(c.logger, "\x1b[%dm%02d:%02d:%02d %-10s |\x1b[0m %s\n",
				clr,
				hour, min, sec, sid,
				sc.Text(),
			)
		} else {
			fmt.Fprintf(c.logger, "%02d:%02d:%02d %-10s | %s\n", hour, min, sec, sid, sc.Text())
		}
	}
}
<commit_msg>Modified code error handling<commit_after>package golet

import (
	"bufio"
	"context"
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"os/signal"
	"runtime"
	"sync"
	"syscall"
	"time"

	"github.com/Code-Hex/golet/internal/port"
	colorable "github.com/mattn/go-colorable"
	"github.com/robfig/cron"
)

type color int

const (
	red color = iota // + 31
	green
	yellow
	blue
	magenta
	cyan

	colornum int = 5
)

// config is main struct.
// struct comments from http://search.cpan.org/dist/Proclet/lib/Proclet.pm
// Proclet is a great module!!
type config struct {
	interval   time.Duration // interval in seconds between spawning services unless a service exits abnormally.
	color      bool          // colored log.
	logger     io.Writer     // sets the output destination file. use stderr by default.
	logWorker  bool          // enable worker for format logs. If disabled this option, cannot use logger opt too.
	execNotice bool          // enable start and exec notice message like: `16:38:12 worker.1 | Start callback: worker``.

	services   []Service
	wg         sync.WaitGroup
	once       sync.Once
	cancel     func()
	ctx        *signalCtx
	serviceNum int
	tags       map[string]bool
	cron       *cron.Cron
}

var shell []string

func init() {
	if runtime.GOOS == "windows" {
		path, err := exec.LookPath("cmd")
		if err != nil {
			panic("Could not find `cmd` command")
		}
		shell = []string{path, "/c"}
	} else {
		path, err := exec.LookPath("bash")
		if err != nil {
			panic("Could not find `bash` command")
		}
		shell = []string{path, "-c"}
	}
}

// Runner interface have methods for configuration and to run services.
type Runner interface {
	SetInterval(time.Duration)
	EnableColor()
	SetLogger(io.Writer)
	DisableLogger()
	DisableExecNotice()
	Env(map[string]string) error
	Add(...Service) error
	Run() error
}

// for settings
// SetInterval can specify the interval at which the command is executed.
func (c *config) SetInterval(t time.Duration) { c.interval = t }

// EnableColor can output colored log.
func (c *config) EnableColor() { c.color = true }

// SetLogger can specify the io.Writer
// for example in https://github.com/lestrrat/go-file-rotatelogs
/*
      logf, _ := rotatelogs.New(
  	    "/path/to/access_log.%Y%m%d%H%M",
  	    rotatelogs.WithLinkName("/path/to/access_log"),
  	    rotatelogs.WithMaxAge(24 * time.Hour),
  	    rotatelogs.WithRotationTime(time.Hour),
      )

	  golet.New(context.Background()).SetLogger(logf)
*/
func (c *config) SetLogger(f io.Writer) { c.logger = f }

// DisableLogger is prevent to output log
func (c *config) DisableLogger() { c.logWorker = false }

// DisableExecNotice is disable execute notifications
func (c *config) DisableExecNotice() { c.execNotice = false }

// New to create struct of golet.
func New(c context.Context) Runner {
	ctx, cancel := context.WithCancel(c)
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, syscall.SIGHUP, syscall.SIGTERM, syscall.SIGINT)
	return &config{
		interval:   0,
		color:      false,
		logger:     colorable.NewColorableStderr(),
		logWorker:  true,
		execNotice: true,

		ctx: &signalCtx{
			parent:  ctx,
			sigchan: signals,
		},
		cancel: cancel,
		tags:   map[string]bool{},
		cron:   cron.New(),
	}
}

// Env can add temporary environment variables.
func (c *config) Env(envs map[string]string) error {
	for k := range envs {
		if e := os.Setenv(k, envs[k]); e != nil {
			return e
		}
	}
	return nil
}

// Add can add runnable services
func (c *config) Add(services ...Service) error {
	for _, service := range services {
		c.serviceNum++
		if service.Tag == "" {
			service.Tag = fmt.Sprintf("%d", c.serviceNum)
		}
		if service.Worker <= 0 {
			service.Worker = 1
		}
		if _, ok := c.tags[service.Tag]; ok {
			return errors.New("tag: " + service.Tag + " is already exists")
		}
		c.tags[service.Tag] = true

		n, err := port.GetPort()
		if err != nil {
			return err
		}

		service.tmpPort = n
		service.color = color(c.serviceNum%colornum + 32)

		c.services = append(c.services, service)
	}
	return nil
}

// Run just like the name.
func (c *config) Run() error {
	services := make(map[string]Service)

	order := make([]string, 0, c.calcCapacitySize())

	// Assign services.
	if err := c.assign(&order, services); err != nil {
		return err
	}
	chps := make(chan *os.Process, 1)
	go c.waitSignals(chps, len(order))

	// Invoke workers.
	for _, sid := range order {
		service := services[sid]
		if service.isExecute() {
			// Execute the command with cron or goroutine
			if service.isCron() {
				c.addCmd(service, chps)
			} else {
				c.wg.Add(1)
				go func() {
					defer func() {
						service.ctx.Close()
						c.wg.Done()
					}()
				PROCESS:
					for {
						// Notify you have executed the command
						if c.execNotice {
							service.Printf("Exec command: %s\n", service.Exec)
						}
						select {
						case <-c.ctx.Done():
							return
						default:
							// If golet is recieved signal or exit code is 0, golet do not restart process.
							if err := run(service.prepare(), chps); err != nil {
								if exiterr, ok := err.(*exec.ExitError); ok {
									// See https://stackoverflow.com/a/10385867
									if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
										if !status.Signaled() {
											continue PROCESS
										}
										return
									}
								}
							}
							return
						}
					}
				}()
			}
		}

		if service.isCode() {
			// Run callback with cron or goroutine
			if service.isCron() {
				c.addTask(service)
			} else {
				c.wg.Add(1)
				go func() {
					defer func() {
						service.ctx.Close()
						c.wg.Done()
					}()
					// If this callback is dead, we should restart it. (like a supervisor)
					// So, this loop for that.
				CALLBACK:
					for {
						// Notify you have run the callback
						if c.execNotice {
							service.Printf("Callback: %s\n", service.Tag)
						}
						select {
						case <-c.ctx.Done():
							return
						default:
							if err := service.Code(service.ctx); err != nil {
								service.Printf("Callback Error: %s\n", err.Error())
								continue CALLBACK
							}
							return
						}
					}
				}()
			}
		}
		// Enable log worker if logWorker is true.
		if c.logWorker && (service.Code != nil || service.Exec != "") {
			rd := service.reader
			go c.logging(bufio.NewScanner(rd), sid, service.color)
		}
		// When the task is cron, it does not cause wait time.
		if service.Every == "" {
			time.Sleep(c.interval)
		}
	}

	c.wait(chps)

	return nil
}

// Calculate of the number of workers.
func (c *config) calcCapacitySize() (cap int) {
	for _, service := range c.services {
		cap += service.Worker
	}
	return
}

// Assign the service ID.
// It also make `order` slice to keep key order of `map[string]Service`.
func (c *config) assign(order *[]string, services map[string]Service) error {
	for _, service := range c.services {
		worker := service.Worker
		for i := 1; i <= worker; i++ {
			s := service
			if err := s.createContext(c.ctx, i); err != nil {
				return err
			}
			sid := fmt.Sprintf("%s.%d", s.Tag, i)
			services[sid] = s
			*order = append(*order, sid)
		}
	}
	return nil
}

// Receive process ID to be executed. or
// It traps the signal relate to parent process. sends a signal to the received process ID.
func (c *config) waitSignals(chps <-chan *os.Process, cap int) {
	procs := make([]*os.Process, 0, cap)
Loop:
	for {
		select {
		case proc := <-chps:
			// Replace used process(nil) with the newly generated process.
			// This run to reduce the memory allocation frequency.
			for i, p := range procs {
				if p == nil {
					procs[i] = proc
					continue Loop
				}
			}
			// If using all processes, allocate newly.
			procs = append(procs, proc)
		case c.ctx.signal = <-c.ctx.sigchan:
			switch c.ctx.signal {
			case syscall.SIGTERM, syscall.SIGHUP:
				c.ctx.signal = syscall.SIGTERM
				sendSignal2Procs(syscall.SIGTERM, procs)
				c.ctx.notifySignal()
			case syscall.SIGINT:
				sendSignal2Procs(syscall.SIGINT, procs)
				c.ctx.notifySignal()
			}
		case <-c.ctx.Done():
			c.cron.Stop()
			return
		}
	}
}

// sendSignal2Procs can send signal and replace os.Process struct of the terminated process with nil
func sendSignal2Procs(sig syscall.Signal, procs []*os.Process) {
	for i, p := range procs {
		if p != nil {
			p.Signal(sig)
			// In case of error, the process has already finished.
			if _, err := p.Wait(); err != nil {
				procs[i] = nil
			}
		}
	}
}

// Execute the command and send its process ID.
func run(c *exec.Cmd, chps chan<- *os.Process) error {
	if err := c.Start(); err != nil {
		return err
	}
	chps <- c.Process
	return c.Wait()
}

// Add a task to execute the command to cron.
func (c *config) addCmd(s Service, chps chan<- *os.Process) {
	// Notify you have executed the command
	if c.execNotice {
		s.Printf("Exec command: %s\n", s.Exec)
	}
	c.cron.AddFunc(s.Every, func() {
		run(s.prepare(), chps)
	})
}

// Add a task to execute the code block to cron.
func (c *config) addTask(s Service) {
	// Notify you have run the callback
	if c.execNotice {
		s.Printf("Callback: %s\n", s.Tag)
	}
	c.cron.AddFunc(s.Every, func() {
		if err := s.Code(s.ctx); err != nil {
			s.Printf("Callback Error: %s\n", err.Error())
		}
	})
}

// Wait services
func (c *config) wait(chps chan<- *os.Process) {
	c.cron.Start()
	c.wg.Wait()
	signal.Stop(c.ctx.sigchan)
}

// Logging
func (c *config) logging(sc *bufio.Scanner, sid string, clr color) {
	for sc.Scan() {
		hour, min, sec := time.Now().Clock()
		if c.color {
			fmt.Fprintf(c.logger, "\x1b[%dm%02d:%02d:%02d %-10s |\x1b[0m %s\n",
				clr,
				hour, min, sec, sid,
				sc.Text(),
			)
		} else {
			fmt.Fprintf(c.logger, "%02d:%02d:%02d %-10s | %s\n", hour, min, sec, sid, sc.Text())
		}
	}
}
<|endoftext|>


<commit_before>package gorma

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

	"github.com/raphael/goa/design"
	"github.com/raphael/goa/goagen/codegen"
	"gopkg.in/alecthomas/kingpin.v2"
)

// Generator is the application code generator.
type Generator struct {
	genfiles []string
}

// Generate is the generator entry point called by the meta generator.
func Generate(api *design.APIDefinition) ([]string, error) {
	g, err := NewGenerator()
	if err != nil {
		return nil, err
	}
	return g.Generate(api)
}

// NewGenerator returns the application code generator.
func NewGenerator() (*Generator, error) {
	return new(Generator), nil
}

// Generate produces the skeleton main.
func (g *Generator) Generate(api *design.APIDefinition) ([]string, error) {

	os.RemoveAll(ModelDir())
	os.MkdirAll(ModelDir(), 0755)
	app := kingpin.New("Model generator", "model generator")
	codegen.RegisterFlags(app)
	_, err := app.Parse(os.Args[1:])
	if err != nil {
		panic(err)
	}
	imp, err := filepath.Rel(filepath.Join(os.Getenv("GOPATH"), "src"), codegen.OutputDir)
	if err != nil {
		return nil, err
	}
	imp = filepath.Join(imp, "app")
	imports := []*codegen.ImportSpec{
		codegen.SimpleImport(imp),
		codegen.SimpleImport("github.com/jinzhu/gorm"),
		codegen.SimpleImport("github.com/jinzhu/copier"),
		codegen.SimpleImport("database/sql"),
	}

	rbacimports := []*codegen.ImportSpec{
		codegen.SimpleImport(imp),
		codegen.SimpleImport("github.com/mikespook/gorbac"),
	}

	rbactitle := fmt.Sprintf("%s: RBAC", api.Name)
	_, dorbac := api.Metadata["github.com/bketelsen/gorma#rbac"]

	err = api.IterateUserTypes(func(res *design.UserTypeDefinition) error {
		if res.Type.IsObject() {
			title := fmt.Sprintf("%s: Models", api.Name)
			modelname := strings.ToLower(Demodel(res.TypeName))
			filename := filepath.Join(ModelDir(), modelname+"_model.go")
			mtw, err := NewModelWriter(filename)
			if err != nil {
				panic(err)
			}
			mtw.WriteHeader(title, "models", imports)
			if md, ok := res.Metadata["github.com/bketelsen/gorma"]; ok && md == "Model" {
				fmt.Println("Found Gorma Metadata:", md)
				err = mtw.Execute(res)
				if err != nil {
					g.Cleanup()
					return err
				}
			}
			if err := mtw.FormatCode(); err != nil {
				g.Cleanup()

			}
			if err != nil {
				g.genfiles = append(g.genfiles, filename)
			}
			return nil
		}

		return nil

	})
	if dorbac {
		rbacfilename := filepath.Join(ModelDir(), "rbac.go")
		rbacw, err := NewRbacWriter(rbacfilename)
		if err != nil {
			panic(err)
		}
		rbacw.WriteHeader(rbactitle, "models", rbacimports)
		err = rbacw.Execute(api)
		if err != nil {
			g.Cleanup()
			return g.genfiles, err
		}
		if err := rbacw.FormatCode(); err != nil {
			g.Cleanup()
			return nil, err
		}
		if err != nil {
			g.genfiles = append(g.genfiles, rbacfilename)
		}

	}

	return g.genfiles, err
}

// Cleanup removes all the files generated by this generator during the last invokation of Generate.
func (g *Generator) Cleanup() {
	for _, f := range g.genfiles {
		os.Remove(f)
	}
	g.genfiles = nil
}
<commit_msg>trying it<commit_after>package gorma

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

	"github.com/raphael/goa/design"
	"github.com/raphael/goa/goagen/codegen"
	"gopkg.in/alecthomas/kingpin.v2"
)

// Generator is the application code generator.
type Generator struct {
	genfiles []string
}

// Generate is the generator entry point called by the meta generator.
func Generate(api *design.APIDefinition) ([]string, error) {
	g, err := NewGenerator()
	if err != nil {
		return nil, err
	}
	return g.Generate(api)
}

// NewGenerator returns the application code generator.
func NewGenerator() (*Generator, error) {
	return new(Generator), nil
}

// Generate produces the skeleton main.
func (g *Generator) Generate(api *design.APIDefinition) ([]string, error) {

	os.RemoveAll(ModelDir())
	os.MkdirAll(ModelDir(), 0755)
	app := kingpin.New("Model generator", "model generator")
	codegen.RegisterFlags(app)
	_, err := app.Parse(os.Args[1:])
	if err != nil {
		panic(err)
	}
	imp, err := filepath.Rel(filepath.Join(os.Getenv("GOPATH"), "src"), codegen.OutputDir)
	if err != nil {
		return nil, err
	}
	imp = filepath.Join(imp, "app")
	imports := []*codegen.ImportSpec{
		codegen.SimpleImport(imp),
		codegen.SimpleImport("github.com/jinzhu/gorm"),
		codegen.SimpleImport("github.com/jinzhu/copier"),
		codegen.SimpleImport("database/sql"),
	}

	rbacimports := []*codegen.ImportSpec{
		codegen.SimpleImport(imp),
		codegen.SimpleImport("github.com/mikespook/gorbac"),
	}

	rbactitle := fmt.Sprintf("%s: RBAC", api.Name)
	_, dorbac := api.Metadata["github.com/bketelsen/gorma#rbac"]

	err = api.IterateUserTypes(func(res *design.UserTypeDefinition) error {
		if res.Type.IsObject() {
			title := fmt.Sprintf("%s: Models", api.Name)
			modelname := strings.ToLower(DeMmodel(res.TypeName))
			filename := filepath.Join(ModelDir(), modelname+"_model.go")
			mtw, err := NewModelWriter(filename)
			if err != nil {
				panic(err)
			}
			mtw.WriteHeader(title, "models", imports)
			if md, ok := res.Metadata["github.com/bketelsen/gorma"]; ok && md == "Model" {
				fmt.Println("Found Gorma Metadata:", md)
				err = mtw.Execute(res)
				if err != nil {
					g.Cleanup()
					return err
				}
			}
			if err := mtw.FormatCode(); err != nil {
				g.Cleanup()

			}
			if err != nil {
				g.genfiles = append(g.genfiles, filename)
			}
			return nil
		}

		return nil

	})
	if dorbac {
		rbacfilename := filepath.Join(ModelDir(), "rbac.go")
		rbacw, err := NewRbacWriter(rbacfilename)
		if err != nil {
			panic(err)
		}
		rbacw.WriteHeader(rbactitle, "models", rbacimports)
		err = rbacw.Execute(api)
		if err != nil {
			g.Cleanup()
			return g.genfiles, err
		}
		if err := rbacw.FormatCode(); err != nil {
			g.Cleanup()
			return nil, err
		}
		if err != nil {
			g.genfiles = append(g.genfiles, rbacfilename)
		}

	}

	return g.genfiles, err
}

// Cleanup removes all the files generated by this generator during the last invokation of Generate.
func (g *Generator) Cleanup() {
	for _, f := range g.genfiles {
		os.Remove(f)
	}
	g.genfiles = nil
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"errors"
	"flag"
	"fmt"
	"io"
	"os"
	"os/user"
	"path"
	"path/filepath"
	"regexp"
	"strings"

	"log"

	"code.google.com/p/go.crypto/openpgp"
	"code.google.com/p/go.crypto/openpgp/armor"
	"code.google.com/p/gopass"
)

var secringPath = "~/.gnupg/secring.gpg"
var prompt = "password: "

func main() {
	var regex *regexp.Regexp
	var err error

	directoryRootPtr := flag.String("s", "", "Directory")
	grepStringPtr := flag.String("g", "", "Regex String")
	recipientEmailPtr := flag.String("r", "", "Recipient Email")
	flag.Parse()

	if *recipientEmailPtr == "" {
		Usage()
		fmt.Println("Recipient email must be specified")
		os.Exit(1)
	}

	if *directoryRootPtr == "" {
		Usage()
		fmt.Println("Root directory must be specified")
		os.Exit(1)
	}

	if *grepStringPtr != "" {
		regex, err = regexp.Compile(*grepStringPtr)
		if err != nil {
			log.Fatal(err)
		}
	}

	secringPath, _ = expandPath(secringPath)
	privringFile, err := os.Open(secringPath)
	if err != nil {
		log.Fatal(err)
		return
	}

	privring, err := openpgp.ReadKeyRing(privringFile)
	if err != nil {
		log.Fatal(err)
		return
	}

	password, err := gopass.GetPass(prompt)
	if err != nil {
		log.Fatal(err)
		return
	}

	fileCallback := func(path string, fi os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if fi.IsDir() {
			return nil
		}
		if filepath.Ext(fi.Name()) == ".gpg" {
			return decryptFile(*recipientEmailPtr, password, path, regex, privring)
		}
		return nil
	}

	filesPath := path.Join(*directoryRootPtr, "files")
	err = filepath.Walk(filesPath, fileCallback)
	if err != nil {
		log.Fatal(err)
	}
}

func getKeyByEmail(keyring openpgp.EntityList, email string) *openpgp.Entity {
	for _, entity := range keyring {
		for _, ident := range entity.Identities {
			if ident.UserId.Email == email {
				return entity
			}
		}
	}
	return nil
}

func expandPath(p string) (string, error) {
	if path.IsAbs(p) {
		return p, nil
	}
	if p[:2] == "~/" {
		usr, err := user.Current()
		if err != nil {
			return "", err
		}
		p = strings.Replace(p, "~", usr.HomeDir, 1)
	}
	return p, nil
}

func decryptFile(recipient, password, filePath string, regex *regexp.Regexp, privring openpgp.EntityList) error {
	secfile, err := os.Open(filePath)
	if err != nil {
		return err
	}

	block, err := armor.Decode(secfile)
	if err != nil {
		return err
	}

	recipientEntity := getKeyByEmail(privring, recipient)
	if recipientEntity == nil {
		return errors.New("Invalid Recipient")
	}

	ents := openpgp.EntityList([]*openpgp.Entity{recipientEntity})

	promptCallback := func(keys []openpgp.Key, symmetric bool) ([]byte, error) {
		for _, k := range keys {
			err := k.PrivateKey.Decrypt([]byte(password))
			if err == nil {
				return nil, nil
			}
		}
		return nil, errors.New("invalid password or no private key")
	}

	md, err := openpgp.ReadMessage(block.Body, ents, promptCallback, nil)
	if err != nil {
		return err
	}

	if regex != nil {
		first := true
		lineNumber := 0
		foundMatch := false

		scanner := bufio.NewScanner(md.UnverifiedBody)
		for scanner.Scan() {
			lineNumber++
			line := scanner.Text()
			if regex.Match([]byte(line)) {
				foundMatch = true
				if first {
					fmt.Println(filePath)
					first = false
				}
				fmt.Printf("%v:%v\n", lineNumber, line)
			}
		}

		if foundMatch {
			fmt.Println()
		}
	} else {
		io.Copy(os.Stdout, md.UnverifiedBody)
	}
	return nil
}

var Usage = func() {
	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
	flag.PrintDefaults()
}
<commit_msg>modularize<commit_after>package main

import (
	"bufio"
	"errors"
	"flag"
	"fmt"
	"io"
	"os"
	"os/user"
	"path"
	"path/filepath"
	"regexp"
	"strings"

	"log"

	"code.google.com/p/go.crypto/openpgp"
	"code.google.com/p/go.crypto/openpgp/armor"
	"code.google.com/p/gopass"
)

var DefaultSecureRingPath = "~/.gnupg/secring.gpg"
var DefaultPrompt = "password: "

func main() {
	directoryRootPtr := flag.String("s", "", "Directory")
	grepStringPtr := flag.String("g", "", "Regex String")
	recipientEmailPtr := flag.String("r", "", "Recipient Email")
	flag.Parse()

	if *recipientEmailPtr == "" {
		Usage()
		fmt.Println("Recipient email must be specified")
		os.Exit(1)
	}

	if *directoryRootPtr == "" {
		Usage()
		fmt.Println("Root directory must be specified")
		os.Exit(1)
	}

	ctx := NewSecureContext(
		DefaultSecureRingPath,
		*recipientEmailPtr,
		*directoryRootPtr,
	)

	err := ctx.ReadKeyRing()
	if err != nil {
		log.Fatal(err)
		return
	}

	_, err = ctx.GetPassword()
	if err != nil {
		log.Fatal(err)
		return
	}

	ctx.FindRegex(*grepStringPtr)
}

type SecureContext struct {
	SecureRingPath string
	EmailRecipient string
	DirectoryRoot  string

	PrivateRing openpgp.EntityList
	Password    string

	SearchRegex *regexp.Regexp
}

func NewSecureContext(secureRingPath, emailRecipient, directoryRoot string) *SecureContext {
	return &SecureContext{
		SecureRingPath: secureRingPath,
		EmailRecipient: emailRecipient,
		DirectoryRoot:  directoryRoot,
	}
}

func (ctx *SecureContext) GetPassword() (string, error) {
	var err error
	ctx.Password, err = gopass.GetPass(DefaultPrompt)
	if err != nil {
		log.Fatal(err)
		return "", err
	}
	return ctx.Password, nil
}

func (ctx *SecureContext) ReadKeyRing() error {
	secringPath, _ := expandPath(ctx.SecureRingPath)
	privringFile, err := os.Open(secringPath)
	if err != nil {
		return err
	}
	defer privringFile.Close()

	ctx.PrivateRing, err = openpgp.ReadKeyRing(privringFile)
	if err != nil {
		return err
	}

	return nil
}

func (ctx *SecureContext) FindRegex(regexStr string) error {
	var regex *regexp.Regexp
	var err error

	if len(regexStr) > 0 {
		regex, err = regexp.Compile(regexStr)
		if err != nil {
			return err
		}
	}

	fileCallback := func(path string, fi os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if fi.IsDir() {
			return nil
		}
		if filepath.Ext(fi.Name()) != ".gpg" {
			return nil
		}

		md, err := ctx.DecryptFile(path, regex)
		if err != nil {
			return err
		}

		if regex != nil {
			first := true
			lineNumber := 0
			foundMatch := false

			scanner := bufio.NewScanner(md.UnverifiedBody)
			for scanner.Scan() {
				lineNumber++
				line := scanner.Text()
				if regex.Match([]byte(line)) {
					foundMatch = true
					if first {
						fmt.Println(path)
						first = false
					}
					fmt.Printf("%v:%v\n", lineNumber, line)
				}
			}

			if foundMatch {
				fmt.Println()
			}
		} else {
			io.Copy(os.Stdout, md.UnverifiedBody)
		}

		return nil
	}

	filesPath := path.Join(ctx.DirectoryRoot, "files")
	if err = filepath.Walk(filesPath, fileCallback); err != nil {
		return err
	}
	return nil
}

func (ctx *SecureContext) GetKeyByEmail() *openpgp.Entity {
	for _, entity := range ctx.PrivateRing {
		for _, ident := range entity.Identities {
			if ident.UserId.Email == ctx.EmailRecipient {
				return entity
			}
		}
	}
	return nil
}

func (ctx *SecureContext) DecryptFile(filePath string, regex *regexp.Regexp) (*openpgp.MessageDetails, error) {
	secfile, err := os.Open(filePath)
	if err != nil {
		return nil, err
	}
	defer secfile.Close()

	block, err := armor.Decode(secfile)
	if err != nil {
		return nil, err
	}

	recipientEntity := ctx.GetKeyByEmail()
	if recipientEntity == nil {
		return nil, errors.New("Invalid Recipient")
	}

	ents := openpgp.EntityList([]*openpgp.Entity{recipientEntity})

	promptCallback := func(keys []openpgp.Key, symmetric bool) ([]byte, error) {
		for _, k := range keys {
			err := k.PrivateKey.Decrypt([]byte(ctx.Password))
			if err == nil {
				return nil, nil
			}
		}
		return nil, errors.New("invalid password or no private key")
	}

	return openpgp.ReadMessage(block.Body, ents, promptCallback, nil)
}

func expandPath(p string) (string, error) {
	if path.IsAbs(p) {
		return p, nil
	}
	if p[:2] == "~/" {
		usr, err := user.Current()
		if err != nil {
			return "", err
		}
		p = strings.Replace(p, "~", usr.HomeDir, 1)
	}
	return p, nil
}

var Usage = func() {
	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
	flag.PrintDefaults()
}
<|endoftext|>


<commit_before>// Package goflow implements a dataflow and flow-based programming library for Go.
package goflow

import (
	"fmt"
	"reflect"
	"sync"
)

// GraphConfig sets up properties for a graph.
type GraphConfig struct {
	BufferSize int
}

// Graph represents a graph of processes connected with packet channels.
type Graph struct {
	conf                   GraphConfig            // Graph configuration
	waitGrp                *sync.WaitGroup        // Wait group for a graceful termination
	procs                  map[string]interface{} // Network processes
	inPorts                map[string]port        // Map of network incoming ports to component ports
	outPorts               map[string]port        // Map of network outgoing ports to component ports
	connections            []connection           // Network graph edges (inter-process connections)
	chanListenersCount     map[uintptr]uint       // Tracks how many outports use the same channel
	chanListenersCountLock sync.Locker            // Used to synchronize operations on the chanListenersCount map
	iips                   []iip                  // Initial Information Packets to be sent to the network on start
}

// NewGraph returns a new initialized empty graph instance.
func NewGraph(config ...GraphConfig) *Graph {
	conf := GraphConfig{}
	if len(config) == 1 {
		conf = config[0]
	}

	return &Graph{
		conf:                   conf,
		waitGrp:                new(sync.WaitGroup),
		procs:                  make(map[string]interface{}),
		inPorts:                make(map[string]port),
		outPorts:               make(map[string]port),
		chanListenersCount:     make(map[uintptr]uint),
		chanListenersCountLock: new(sync.Mutex),
	}
}

// NewDefaultGraph is a ComponentConstructor for the factory.
func NewDefaultGraph() interface{} {
	return NewGraph()
}

// // Register an empty graph component in the registry
// func init() {
// 	Register("Graph", NewDefaultGraph)
// 	Annotate("Graph", ComponentInfo{
// 		Description: "A clear graph",
// 		Icon:        "cogs",
// 	})
// }

// Add adds a new process with a given name to the network.
func (n *Graph) Add(name string, c interface{}) error {
	// c should be either graph or a component
	_, isComponent := c.(Component)
	_, isGraph := c.(Graph)

	if !isComponent && !isGraph {
		return fmt.Errorf("could not add process '%s': instance is neither Component nor Graph", name)
	}
	// Add to the map of processes
	n.procs[name] = c

	return nil
}

// AddGraph adds a new blank graph instance to a network. That instance can
// be modified then at run-time.
func (n *Graph) AddGraph(name string) error {
	return n.Add(name, NewDefaultGraph())
}

// AddNew creates a new process instance using component factory and adds it to the network.
func (n *Graph) AddNew(processName string, componentName string, f *Factory) error {
	proc, err := f.Create(componentName)
	if err != nil {
		return err
	}

	return n.Add(processName, proc)
}

// Remove deletes a process from the graph. First it stops the process if running.
// Then it disconnects it from other processes and removes the connections from
// the graph. Then it drops the process itself.
func (n *Graph) Remove(processName string) error {
	if _, exists := n.procs[processName]; !exists {
		return fmt.Errorf("could not remove process: '%s' does not exist", processName)
	}

	delete(n.procs, processName)

	return nil
}

// // Rename changes a process name in all connections, external ports, IIPs and the
// // graph itself.
// func (n *Graph) Rename(processName, newName string) bool {
// 	if _, exists := n.procs[processName]; !exists {
// 		return false
// 	}
// 	if _, busy := n.procs[newName]; busy {
// 		// New name is already taken
// 		return false
// 	}
// 	for i, conn := range n.connections {
// 		if conn.src.proc == processName {
// 			n.connections[i].src.proc = newName
// 		}
// 		if conn.tgt.proc == processName {
// 			n.connections[i].tgt.proc = newName
// 		}
// 	}
// 	for key, port := range n.inPorts {
// 		if port.proc == processName {
// 			tmp := n.inPorts[key]
// 			tmp.proc = newName
// 			n.inPorts[key] = tmp
// 		}
// 	}
// 	for key, port := range n.outPorts {
// 		if port.proc == processName {
// 			tmp := n.outPorts[key]
// 			tmp.proc = newName
// 			n.outPorts[key] = tmp
// 		}
// 	}
// 	n.procs[newName] = n.procs[processName]
// 	delete(n.procs, processName)
// 	return true
// }

// // Get returns a node contained in the network by its name.
// func (n *Graph) Get(processName string) interface{} {
// 	if proc, ok := n.procs[processName]; ok {
// 		return proc
// 	} else {
// 		panic("Process with name '" + processName + "' was not found")
// 	}
// }

// // getWait returns net's wait group.
// func (n *Graph) getWait() *sync.WaitGroup {
// 	return n.waitGrp
// }

// Process runs the network.
func (n *Graph) Process() {
	err := n.sendIIPs()
	if err != nil {
		// TODO provide a nicer way to handle graph errors
		panic(err)
	}

	for _, i := range n.procs {
		c, ok := i.(Component)
		if !ok {
			continue
		}

		n.waitGrp.Add(1)

		w := Run(c)
		proc := i

		go func() {
			<-w
			n.closeProcOuts(proc)
			n.waitGrp.Done()
		}()
	}

	n.waitGrp.Wait()
}

func (n *Graph) closeProcOuts(proc interface{}) {
	val := reflect.ValueOf(proc).Elem()
	for i := 0; i < val.NumField(); i++ {
		field := val.Field(i)
		fieldType := field.Type()

		if !(field.IsValid() && field.Kind() == reflect.Chan && field.CanSet() &&
			fieldType.ChanDir()&reflect.SendDir != 0 && fieldType.ChanDir()&reflect.RecvDir == 0) {
			continue
		}

		if n.decChanListenersCount(field) {
			field.Close()
		}
	}
}
<commit_msg>ignore nil chan , or it may cause close nil error<commit_after>// Package goflow implements a dataflow and flow-based programming library for Go.
package goflow

import (
	"fmt"
	"reflect"
	"sync"
)

// GraphConfig sets up properties for a graph.
type GraphConfig struct {
	BufferSize int
}

// Graph represents a graph of processes connected with packet channels.
type Graph struct {
	conf                   GraphConfig            // Graph configuration
	waitGrp                *sync.WaitGroup        // Wait group for a graceful termination
	procs                  map[string]interface{} // Network processes
	inPorts                map[string]port        // Map of network incoming ports to component ports
	outPorts               map[string]port        // Map of network outgoing ports to component ports
	connections            []connection           // Network graph edges (inter-process connections)
	chanListenersCount     map[uintptr]uint       // Tracks how many outports use the same channel
	chanListenersCountLock sync.Locker            // Used to synchronize operations on the chanListenersCount map
	iips                   []iip                  // Initial Information Packets to be sent to the network on start
}

// NewGraph returns a new initialized empty graph instance.
func NewGraph(config ...GraphConfig) *Graph {
	conf := GraphConfig{}
	if len(config) == 1 {
		conf = config[0]
	}

	return &Graph{
		conf:                   conf,
		waitGrp:                new(sync.WaitGroup),
		procs:                  make(map[string]interface{}),
		inPorts:                make(map[string]port),
		outPorts:               make(map[string]port),
		chanListenersCount:     make(map[uintptr]uint),
		chanListenersCountLock: new(sync.Mutex),
	}
}

// NewDefaultGraph is a ComponentConstructor for the factory.
func NewDefaultGraph() interface{} {
	return NewGraph()
}

// // Register an empty graph component in the registry
// func init() {
// 	Register("Graph", NewDefaultGraph)
// 	Annotate("Graph", ComponentInfo{
// 		Description: "A clear graph",
// 		Icon:        "cogs",
// 	})
// }

// Add adds a new process with a given name to the network.
func (n *Graph) Add(name string, c interface{}) error {
	// c should be either graph or a component
	_, isComponent := c.(Component)
	_, isGraph := c.(Graph)

	if !isComponent && !isGraph {
		return fmt.Errorf("could not add process '%s': instance is neither Component nor Graph", name)
	}
	// Add to the map of processes
	n.procs[name] = c

	return nil
}

// AddGraph adds a new blank graph instance to a network. That instance can
// be modified then at run-time.
func (n *Graph) AddGraph(name string) error {
	return n.Add(name, NewDefaultGraph())
}

// AddNew creates a new process instance using component factory and adds it to the network.
func (n *Graph) AddNew(processName string, componentName string, f *Factory) error {
	proc, err := f.Create(componentName)
	if err != nil {
		return err
	}

	return n.Add(processName, proc)
}

// Remove deletes a process from the graph. First it stops the process if running.
// Then it disconnects it from other processes and removes the connections from
// the graph. Then it drops the process itself.
func (n *Graph) Remove(processName string) error {
	if _, exists := n.procs[processName]; !exists {
		return fmt.Errorf("could not remove process: '%s' does not exist", processName)
	}

	delete(n.procs, processName)

	return nil
}

// // Rename changes a process name in all connections, external ports, IIPs and the
// // graph itself.
// func (n *Graph) Rename(processName, newName string) bool {
// 	if _, exists := n.procs[processName]; !exists {
// 		return false
// 	}
// 	if _, busy := n.procs[newName]; busy {
// 		// New name is already taken
// 		return false
// 	}
// 	for i, conn := range n.connections {
// 		if conn.src.proc == processName {
// 			n.connections[i].src.proc = newName
// 		}
// 		if conn.tgt.proc == processName {
// 			n.connections[i].tgt.proc = newName
// 		}
// 	}
// 	for key, port := range n.inPorts {
// 		if port.proc == processName {
// 			tmp := n.inPorts[key]
// 			tmp.proc = newName
// 			n.inPorts[key] = tmp
// 		}
// 	}
// 	for key, port := range n.outPorts {
// 		if port.proc == processName {
// 			tmp := n.outPorts[key]
// 			tmp.proc = newName
// 			n.outPorts[key] = tmp
// 		}
// 	}
// 	n.procs[newName] = n.procs[processName]
// 	delete(n.procs, processName)
// 	return true
// }

// // Get returns a node contained in the network by its name.
// func (n *Graph) Get(processName string) interface{} {
// 	if proc, ok := n.procs[processName]; ok {
// 		return proc
// 	} else {
// 		panic("Process with name '" + processName + "' was not found")
// 	}
// }

// // getWait returns net's wait group.
// func (n *Graph) getWait() *sync.WaitGroup {
// 	return n.waitGrp
// }

// Process runs the network.
func (n *Graph) Process() {
	err := n.sendIIPs()
	if err != nil {
		// TODO provide a nicer way to handle graph errors
		panic(err)
	}

	for _, i := range n.procs {
		c, ok := i.(Component)
		if !ok {
			continue
		}

		n.waitGrp.Add(1)

		w := Run(c)
		proc := i

		go func() {
			<-w
			n.closeProcOuts(proc)
			n.waitGrp.Done()
		}()
	}

	n.waitGrp.Wait()
}

func (n *Graph) closeProcOuts(proc interface{}) {
	val := reflect.ValueOf(proc).Elem()
	for i := 0; i < val.NumField(); i++ {
		field := val.Field(i)
		fieldType := field.Type()

		if !(field.IsValid() && field.Kind() == reflect.Chan && field.CanSet() &&
			fieldType.ChanDir()&reflect.SendDir != 0 && fieldType.ChanDir()&reflect.RecvDir == 0) {
			continue
		}

		if !field.IsNil() && n.decChanListenersCount(field) {
			field.Close()
		}
	}
}
<|endoftext|>


<commit_before>package main

import "time"

func Tick() {
    time.Sleep(ProbabilisticSleepDuration())
    Distribute(NextDueEvent())
}

func Distribute(event Event) {
}
<commit_msg>thinking a little about when to copy and when not<commit_after>package main

import "time"

func Tick() {
    time.Sleep(ProbabilisticSleepDuration())
    event := NextDueEvent()
    Distribute(&event)
}

func Distribute(event *Event) {

}
<|endoftext|>


<commit_before>package sessions

import (
	"github.com/gin-gonic/gin"
	"Gin_API_Framework/middleware/contrib/secure_cookie"
	"net/http"
)

const (
	COOKIE_MAX_AGE = 122344
	COOKIE_DOMAIN = "*"
	COOKIE_PATH = "/"
)

// set secure cookie
func AuthLogin(c *gin.Context, uid string)  {
	secure_cookie.SetSecureCookie(
		c,
		"user_token",
		uid,
		COOKIE_MAX_AGE,
		COOKIE_PATH,
		COOKIE_DOMAIN,
		true,true)
}

// delete cookie user_token
func AuthLogout(c *gin.Context)  {
	http.SetCookie(c.Writer, &http.Cookie{
		Name:     "user_token",
		Value:    "",
		MaxAge:   -1,
		Path:     COOKIE_PATH,
		Domain:   COOKIE_DOMAIN,
		Secure:   true,
		HttpOnly: true,
	})
}

// Login Require Decorator
func LoginRequired(handle gin.HandlerFunc) gin.HandlerFunc {

	return func(c *gin.Context) {
		userToken, cookie_err := secure_cookie.GetSecureCookie(c,"user_token",1)

		var is_login  bool = true

		if cookie_err != nil{
			is_login = false
		}

		//Tudo 添加查数据库逻辑

		if is_login == false{
			c.JSON(http.StatusUnauthorized,
				gin.H{
					"status":  "failed",
					"desc": "login requierd",
				})
		}else {
			handle(c)
			c.Set("currentUserId",userToken)
			c.Set("currentUser", userToken)
		}
	}
}<commit_msg>更新authlogin authlogout<commit_after>package sessions

import (
	"github.com/gin-gonic/gin"
	"Gin_API_Framework/middleware/contrib/secure_cookie"
	"net/http"
)

const (
	COOKIE_MAX_AGE = 1999999999
	COOKIE_DOMAIN = "www.youku.com"
	COOKIE_PATH = "/"
)

// set secure cookie user_token
func AuthLogin(c *gin.Context, uid string)  {
	secure_cookie.SetSecureCookie(
		c,
		"user_token",
		uid,
		COOKIE_MAX_AGE,
		COOKIE_PATH,
		COOKIE_DOMAIN,
		true,true)
}

// delete cookie user_token
func AuthLogout(c *gin.Context)  {
	http.SetCookie(c.Writer, &http.Cookie{
		Name:     "user_token",
		Value:    "",
		MaxAge:   -1,
		Path:     COOKIE_PATH,
		Domain:   COOKIE_DOMAIN,
		Secure:   true,
		HttpOnly: true,
	})
}

// Login Require Decorator
func LoginRequired(handle gin.HandlerFunc) gin.HandlerFunc {

	return func(c *gin.Context) {
		userToken, cookie_err := secure_cookie.GetSecureCookie(c,"user_token",1)

		var is_login  bool = true

		if cookie_err != nil{
			is_login = false
		}

		//Tudo 添加查数据库逻辑

		if is_login == false{
			c.JSON(http.StatusUnauthorized,
				gin.H{
					"status":  "failed",
					"desc": "login requierd",
				})
		}else {
			handle(c)
			c.Set("currentUserId",userToken)
			c.Set("currentUser", userToken)
		}
	}
}<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	ct "github.com/daviddengcn/go-colortext"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

/*
func GetUserGroupStr(fi os.FileInfo) (usernameStr, groupnameStr string) {
	return "", ""
}
*/

// processCommandLine will return a slice of FileInfos after the filter and exclude expression are processed, and that match a pattern if given.
// It handles if there are no files populated by bash or file not found by bash, and sorts the slice before returning it.
// The returned slice of FileInfos will then be passed to the display rtn to determine how it will be displayed.
func getFileInfosFromCommandLine() []os.FileInfo {
	var fileInfos []os.FileInfo

	HomeDirStr, err := os.UserHomeDir() // used for processing ~ symbol meaning home directory.
	if err != nil {
		fmt.Fprint(os.Stderr, err)
		fmt.Fprintln(os.Stderr, ".  Ignoring HomeDirStr")
		HomeDirStr = ""
	}
	HomeDirStr = HomeDirStr + string(filepath.Separator)

	if flag.NArg() == 0 {
		workingDir, er := os.Getwd()
		if er != nil {
			fmt.Fprintf(os.Stderr, " Error from Linux processCommandLine Getwd is %v\n", er)
			os.Exit(1)
		}
		fileInfos = myReadDir(workingDir)
	} else { // Must have a pattern on the command line, ie, NArg > 0
		pattern := flag.Arg(0) // this only gets the first non flag argument and is all I want on Windows.  And it doesn't panic if there are no arg's.

		if strings.ContainsRune(pattern, ':') {
			directoryAliasesMap = getDirectoryAliases()
			pattern = ProcessDirectoryAliases(directoryAliasesMap, pattern)
		} else if strings.Contains(pattern, "~") { // this can only contain a ~ on Windows.
			pattern = strings.Replace(pattern, "~", HomeDirStr, 1)
		}
		dirName, fileName := filepath.Split(pattern)
		fileName = strings.ToLower(fileName)
		if dirName != "" && fileName == "" { // then have a dir pattern without a filename pattern
			fileInfos = myReadDir(dirName)
			return fileInfos
		}
		if dirName == "" {
			dirName = "."
		}
		if fileName == "" { // need this to not be blank because of the call to Match below.
			fileName = "*"
		}
		if testFlag {
			fmt.Printf(" dirName=%s, fileName=%s \n", dirName, fileName)
		}

		if testFlag {
			fmt.Printf(" dirName=%s, fileName=%s \n", dirName, fileName)
		}

		var filenames []string
		if globFlag {
			// Glob returns the names of all files matching pattern or nil if there is no matching file. The syntax of patterns is the same as in Match.
			// The pattern may describe hierarchical names such as /usr/*/bin/ed (assuming the Separator is '/').  Caveat: it's case sensitive.
			// Glob ignores file system errors such as I/O errors reading directories. The only possible returned error is ErrBadPattern, when pattern is malformed.
			filenames, err = filepath.Glob(pattern)
			if testFlag {
				fmt.Printf(" after glob: len(filenames)=%d, filenames=%v \n\n", len(filenames), filenames)
			}

		} else {
			d, err := os.Open(dirName)
			if err != nil {
				fmt.Fprintf(os.Stderr, " Error from Linux processCommandLine os.Open is %v\n", err)
				os.Exit(1)
			}
			defer d.Close()
			filenames, err = d.Readdirnames(0) // I don't know if I have to make this slice first.  I'm going to assume not for now.
			if err != nil {                    // It seems that ReadDir itself stops when it gets an error of any kind, and I cannot change that.
				fmt.Fprintln(os.Stderr, err, "so calling my own MyReadDir.")
				fileInfos = myReadDir(dirName)
			}

		}

		fileInfos = make([]os.FileInfo, 0, len(filenames))
		const sepStr = string(os.PathSeparator)
		for _, f := range filenames { // basically I do this here because of a pattern to be matched.
			var path string
			if strings.Contains(f, sepStr) {
				path = f
			} else {
				path = dirName + sepStr + f
			}

			fi, err := os.Lstat(path)
			if err != nil {
				fmt.Fprintf(os.Stderr, " Error from Lstat call on %s is %v\n", path, err)
				continue
			}

			match, er := filepath.Match(strings.ToLower(fileName), strings.ToLower(f)) // redundant if glob is used, but I'm ignoring this.
			if er != nil {
				fmt.Fprintf(os.Stderr, " Error from filepath.Match on %s pattern is %v.\n", pattern, er)
				continue
			}

			if includeThis(fi) && match { // has to match pattern, size criteria and not match an exclude pattern.
				fileInfos = append(fileInfos, fi)
			}
			if fi.Mode().IsRegular() && showGrandTotal {
				grandTotal += fi.Size()
				grandTotalCount++
			}
		} // for f ranges over filenames
	} // if flag.NArgs()

	return fileInfos

} // end getFileInfosFromCommandLine

func getColorizedStrings(fiSlice []os.FileInfo, cols int) []colorizedStr {

	cs := make([]colorizedStr, 0, len(fiSlice))

	for i, f := range fiSlice {
		t := f.ModTime().Format("Jan-02-2006_15:04:05")
		sizeStr := ""
		if filenameToBeListedFlag && f.Mode().IsRegular() {
			sizeTotal += f.Size()
			if longFileSizeListFlag {
				sizeStr = strconv.FormatInt(f.Size(), 10) // will convert int64.  Itoa only converts int.  This matters on 386 version.
				if f.Size() > 100000 {
					sizeStr = AddCommas(sizeStr)
				}
				strng := fmt.Sprintf("%16s %s %s", sizeStr, t, f.Name())
				colorized := colorizedStr{color: ct.Yellow, str: strng}
				cs = append(cs, colorized)

			} else {
				var colr ct.Color
				sizeStr, colr = getMagnitudeString(f.Size())
				strng := fmt.Sprintf("%-10s %s %s", sizeStr, t, f.Name())
				colorized := colorizedStr{color: colr, str: strng}
				cs = append(cs, colorized)
			}

		} else if IsSymlink(f.Mode()) {
			s := fmt.Sprintf("%5s %s <%s>", sizeStr, t, f.Name())
			colorized := colorizedStr{color: ct.White, str: s}
			cs = append(cs, colorized)
		} else if dirList && f.IsDir() {
			s := fmt.Sprintf("%5s %s (%s)", sizeStr, t, f.Name())
			colorized := colorizedStr{color: ct.White, str: s}
			cs = append(cs, colorized)
		}
		if i > numOfLines*cols {
			break
		}
	}
	if testFlag {
		fmt.Printf(" In getColorizedString.  len(fiSlice)=%d, len(cs)=%d, numofLines=%d\n", len(fiSlice), len(cs), numOfLines)
	}
	return cs
}
<commit_msg>02/15/2022 05:34:19 PM ds/dsutil_windows.go<commit_after>package main

import (
	"flag"
	"fmt"
	ct "github.com/daviddengcn/go-colortext"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

/*
func GetUserGroupStr(fi os.FileInfo) (usernameStr, groupnameStr string) {
	return "", ""
}
*/

// processCommandLine will return a slice of FileInfos after the filter and exclude expression are processed, and that match a pattern if given.
// It handles if there are no files populated by bash or file not found by bash, and sorts the slice before returning it.
// The returned slice of FileInfos will then be passed to the display rtn to determine how it will be displayed.
func getFileInfosFromCommandLine() []os.FileInfo {
	var fileInfos []os.FileInfo

	HomeDirStr, err := os.UserHomeDir() // used for processing ~ symbol meaning home directory.
	if err != nil {
		fmt.Fprint(os.Stderr, err)
		fmt.Fprintln(os.Stderr, ".  Ignoring HomeDirStr")
		HomeDirStr = ""
	}
	HomeDirStr = HomeDirStr + string(filepath.Separator)

	if flag.NArg() == 0 {
		workingDir, er := os.Getwd()
		if er != nil {
			fmt.Fprintf(os.Stderr, " Error from Linux processCommandLine Getwd is %v\n", er)
			os.Exit(1)
		}
		fileInfos = myReadDir(workingDir)
	} else { // Must have a pattern on the command line, ie, NArg > 0
		pattern := flag.Arg(0) // this only gets the first non flag argument and is all I want on Windows.  And it doesn't panic if there are no arg's.

		if strings.ContainsRune(pattern, ':') {
			directoryAliasesMap = getDirectoryAliases()
			pattern = ProcessDirectoryAliases(directoryAliasesMap, pattern)
		} else if strings.Contains(pattern, "~") { // this can only contain a ~ on Windows.
			pattern = strings.Replace(pattern, "~", HomeDirStr, 1)
		}
		dirName, fileName := filepath.Split(pattern)
		fileName = strings.ToLower(fileName)
		if dirName != "" && fileName == "" { // then have a dir pattern without a filename pattern
			fileInfos = myReadDir(dirName)
			return fileInfos
		}
		if dirName == "" {
			dirName = "."
		}
		if fileName == "" { // need this to not be blank because of the call to Match below.
			fileName = "*"
		}
		if verboseFlag {
			fmt.Printf(" dirName=%s, fileName=%s \n", dirName, fileName)
		}

		if verboseFlag {
			fmt.Printf(" dirName=%s, fileName=%s \n", dirName, fileName)
		}

		var filenames []string
		if globFlag {
			// Glob returns the names of all files matching pattern or nil if there is no matching file. The syntax of patterns is the same as in Match.
			// The pattern may describe hierarchical names such as /usr/*/bin/ed (assuming the Separator is '/').  Caveat: it's case sensitive.
			// Glob ignores file system errors such as I/O errors reading directories. The only possible returned error is ErrBadPattern, when pattern is malformed.
			filenames, err = filepath.Glob(pattern)
			if verboseFlag {
				fmt.Printf(" after glob: len(filenames)=%d, filenames=%v \n\n", len(filenames), filenames)
			}

		} else {
			d, err := os.Open(dirName)
			if err != nil {
				fmt.Fprintf(os.Stderr, " Error from Linux processCommandLine os.Open is %v\n", err)
				os.Exit(1)
			}
			defer d.Close()
			filenames, err = d.Readdirnames(0) // I don't know if I have to make this slice first.  I'm going to assume not for now.
			if err != nil {                    // It seems that ReadDir itself stops when it gets an error of any kind, and I cannot change that.
				fmt.Fprintln(os.Stderr, err, "so calling my own MyReadDir.")
				fileInfos = myReadDir(dirName)
			}

		}

		fileInfos = make([]os.FileInfo, 0, len(filenames))
		const sepStr = string(os.PathSeparator)
		for _, f := range filenames { // basically I do this here because of a pattern to be matched.
			var path string
			if strings.Contains(f, sepStr) {
				path = f
			} else {
				path = dirName + sepStr + f
			}

			fi, err := os.Lstat(path)
			if err != nil {
				fmt.Fprintf(os.Stderr, " Error from Lstat call on %s is %v\n", path, err)
				continue
			}

			match, er := filepath.Match(strings.ToLower(fileName), strings.ToLower(f)) // redundant if glob is used, but I'm ignoring this.
			if er != nil {
				fmt.Fprintf(os.Stderr, " Error from filepath.Match on %s pattern is %v.\n", pattern, er)
				continue
			}

			if includeThis(fi) && match { // has to match pattern, size criteria and not match an exclude pattern.
				fileInfos = append(fileInfos, fi)
			}
			if fi.Mode().IsRegular() && showGrandTotal {
				grandTotal += fi.Size()
				grandTotalCount++
			}
		} // for f ranges over filenames
	} // if flag.NArgs()

	return fileInfos

} // end getFileInfosFromCommandLine

func getColorizedStrings(fiSlice []os.FileInfo, cols int) []colorizedStr {

	cs := make([]colorizedStr, 0, len(fiSlice))

	for i, f := range fiSlice {
		t := f.ModTime().Format("Jan-02-2006_15:04:05")
		sizeStr := ""
		if filenameToBeListedFlag && f.Mode().IsRegular() {
			sizeTotal += f.Size()
			if longFileSizeListFlag {
				sizeStr = strconv.FormatInt(f.Size(), 10) // will convert int64.  Itoa only converts int.  This matters on 386 version.
				if f.Size() > 100000 {
					sizeStr = AddCommas(sizeStr)
				}
				strng := fmt.Sprintf("%16s %s %s", sizeStr, t, f.Name())
				colorized := colorizedStr{color: ct.Yellow, str: strng}
				cs = append(cs, colorized)

			} else {
				var colr ct.Color
				sizeStr, colr = getMagnitudeString(f.Size())
				strng := fmt.Sprintf("%-10s %s %s", sizeStr, t, f.Name())
				colorized := colorizedStr{color: colr, str: strng}
				cs = append(cs, colorized)
			}

		} else if IsSymlink(f.Mode()) {
			s := fmt.Sprintf("%5s %s <%s>", sizeStr, t, f.Name())
			colorized := colorizedStr{color: ct.White, str: s}
			cs = append(cs, colorized)
		} else if dirList && f.IsDir() {
			s := fmt.Sprintf("%5s %s (%s)", sizeStr, t, f.Name())
			colorized := colorizedStr{color: ct.White, str: s}
			cs = append(cs, colorized)
		}
		if i > numOfLines*cols {
			break
		}
	}
	if verboseFlag {
		fmt.Printf(" In getColorizedString.  len(fiSlice)=%d, len(cs)=%d, numofLines=%d\n", len(fiSlice), len(cs), numOfLines)
	}
	return cs
}
<|endoftext|>


<commit_before>package cc_messages

import "encoding/json"

type HealthCheckType string

const UnspecifiedHealthCheckType HealthCheckType = "" // backwards-compatibility
const PortHealthCheckType HealthCheckType = "port"
const NoneHealthCheckType HealthCheckType = "none"

type DesireAppRequestFromCC struct {
	ProcessGuid       string          `json:"process_guid"`
	DropletUri        string          `json:"droplet_uri"`
	DockerImageUrl    string          `json:"docker_image"`
	Stack             string          `json:"stack"`
	StartCommand      string          `json:"start_command"`
	ExecutionMetadata string          `json:"execution_metadata"`
	Environment       Environment     `json:"environment"`
	MemoryMB          int             `json:"memory_mb"`
	DiskMB            int             `json:"disk_mb"`
	FileDescriptors   uint64          `json:"file_descriptors"`
	NumInstances      int             `json:"num_instances"`
	Routes            []string        `json:"routes"`
	LogGuid           string          `json:"log_guid"`
	HealthCheckType   HealthCheckType `json:"health_check_type"`
}

func (d DesireAppRequestFromCC) ToJSON() []byte {
	encoded, _ := json.Marshal(d)
	return encoded
}

type CCDesiredStateServerResponse struct {
	Apps        []DesireAppRequestFromCC `json:"apps"`
	CCBulkToken *json.RawMessage         `json:"token"`
}

type CCBulkToken struct {
	Id int `json:"id"`
}

type KillIndexRequestFromCC struct {
	ProcessGuid string `json:"process_guid"`
	Index       int    `json:"index"`
}
<commit_msg>support health_check_timeout_in_seconds<commit_after>package cc_messages

import "encoding/json"

type HealthCheckType string

const UnspecifiedHealthCheckType HealthCheckType = "" // backwards-compatibility
const PortHealthCheckType HealthCheckType = "port"
const NoneHealthCheckType HealthCheckType = "none"

type DesireAppRequestFromCC struct {
	ProcessGuid                 string          `json:"process_guid"`
	DropletUri                  string          `json:"droplet_uri"`
	DockerImageUrl              string          `json:"docker_image"`
	Stack                       string          `json:"stack"`
	StartCommand                string          `json:"start_command"`
	ExecutionMetadata           string          `json:"execution_metadata"`
	Environment                 Environment     `json:"environment"`
	MemoryMB                    int             `json:"memory_mb"`
	DiskMB                      int             `json:"disk_mb"`
	FileDescriptors             uint64          `json:"file_descriptors"`
	NumInstances                int             `json:"num_instances"`
	Routes                      []string        `json:"routes"`
	LogGuid                     string          `json:"log_guid"`
	HealthCheckType             HealthCheckType `json:"health_check_type"`
	HealthCheckTimeoutInSeconds uint            `json:"health_check_timeout_in_seconds"`
}

func (d DesireAppRequestFromCC) ToJSON() []byte {
	encoded, _ := json.Marshal(d)
	return encoded
}

type CCDesiredStateServerResponse struct {
	Apps        []DesireAppRequestFromCC `json:"apps"`
	CCBulkToken *json.RawMessage         `json:"token"`
}

type CCBulkToken struct {
	Id int `json:"id"`
}

type KillIndexRequestFromCC struct {
	ProcessGuid string `json:"process_guid"`
	Index       int    `json:"index"`
}
<|endoftext|>


<commit_before>// Copyright 2016  Author. 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.

// 把中间件和原本的路由处理器封装在一起， 先执行中间件，如果中间件没有提前结束请求， 最终会把执行权归还给原本的路由处理器。
// 中间件允许注册多个，执行顺序和注册顺序一致。 其实原本的路由处理器也可以看做一个中间件了，不过，它是放在最后一个执行位置上（除了末尾的空中间件）。
// 参考开源项目：https://github.com/urfave/negroni
//
//
//   http.HandleFunc("/log", func)
//   mw := middleware.New()
//   mw.RegisterMiddlewareHandleFunc(Recovery, Token)
//   mw.Run(":9999" )
//
// OR
//
	/*
	package main

	import (
		"fmt"
		"net/http"
	)

	func main() {
		mux := http.NewServeMux()
		mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
			fmt.Fprintf(w, "Welcome to the home page!")
		})

		n := middleware.New()
		n.MuxHandler(mux)
		n.RegisterMiddlewareHandleFunc(Middleware1,Middleware2)
		n.Bootstrap()
		http.ListenAndServe(":3000", n)
	}
	*/
//
package middleware

import "net/http"

//中间件接口
type MiddleWare interface {
	ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
}

type MiddleWareFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)

func (h MiddleWareFunc) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	h(rw, r, next)
}

//中间件列表结构
//适配器模式
type middlewareHandler struct {
	handler MiddleWare
	next    *middlewareHandler
}

func (m *middlewareHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	if nil == m.handler {
		return
	}
	m.handler.ServeHTTP(rw, r, m.next.ServeHTTP)
}

//包装标准库的http.Handler
func Wrap(handler http.Handler) MiddleWare {
	return MiddleWareFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
		handler.ServeHTTP(rw, r)
		next(rw, r)
	})
}

//Cbping是一堆中间件处理程序管理器，
//可以当作http.handler被调用
//通过RegisterMiddlewareHandleFunc|RegisterMiddleWare注册中间件
type Cbping struct {
	//链表头
	//由中间件和路由处理器组建而成
	//路由处理器处于链表末端（除了末尾的空中间件）
	middlewareHead middlewareHandler
	//中间件数组
	middlewares []MiddleWare

	//路由处理器
	//原始路由处理器
	mux http.Handler
}

func (c *Cbping) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	//解析参数
	r.ParseForm()
	//中间件处理
	c.middlewareHead.ServeHTTP(rw, r)
}

//引导初始
func (c *Cbping) Bootstrap() {
	if nil == c.mux {
		c.mux = http.DefaultServeMux
	}
	c.middlewares = append(c.middlewares, Wrap(c.mux))
	c.middlewareHead = build(c.middlewares)
}

//运行
func (c *Cbping) Run(addr string) {
	c.Bootstrap()
	http.ListenAndServe(addr, c)
}

func (c *Cbping) RegisterMiddlewareHandleFunc(handlers ...func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)) {
	for _, handler := range handlers {
		c.RegisterMiddleWare(MiddleWareFunc(handler))
	}

}

//注册中间件
//中间件执行顺序和注册顺序一致
func (c *Cbping) RegisterMiddleWare(handler MiddleWare) {
	c.middlewares = append(c.middlewares, handler)
}

//注册原本路由处理器
func (c *Cbping) MuxHandler(muxHandler http.Handler) {
	c.mux = muxHandler
}

func New() *Cbping {
	return &Cbping{}
}

//递归构建执行链表
func build(handlers []MiddleWare) middlewareHandler {
	var next middlewareHandler

	if len(handlers) == 0 {
		return voidMiddlewareHandler()
	} else if len(handlers) > 1 {
		next = build(handlers[1:])
	} else {
		next = voidMiddlewareHandler()
	}

	return middlewareHandler{handlers[0], &next}
}

func voidMiddlewareHandler() middlewareHandler {
	return middlewareHandler{
		MiddleWareFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {}),
		&middlewareHandler{},
	}
}
<commit_msg>middleware::fmt<commit_after>// Copyright 2016  Author. 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.

// 把中间件和原本的路由处理器封装在一起， 先执行中间件，如果中间件没有提前结束请求， 最终会把执行权归还给原本的路由处理器。
// 中间件允许注册多个，执行顺序和注册顺序一致。 其实原本的路由处理器也可以看做一个中间件了，不过，它是放在最后一个执行位置上（除了末尾的空中间件）。
// 参考开源项目：https://github.com/urfave/negroni
//
//
//   http.HandleFunc("/log", func)
//   mw := middleware.New()
//   mw.RegisterMiddlewareHandleFunc(Recovery, Token)
//   mw.Run(":9999" )
//
// OR
//
/*
	package main

	import (
		"fmt"
		"net/http"
	)

	func main() {
		mux := http.NewServeMux()
		mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
			fmt.Fprintf(w, "Welcome to the home page!")
		})

		n := middleware.New()
		n.MuxHandler(mux)
		n.RegisterMiddlewareHandleFunc(Middleware1,Middleware2)
		n.Bootstrap()
		http.ListenAndServe(":3000", n)
	}
*/
//
package middleware

import "net/http"

//中间件接口
type MiddleWare interface {
	ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
}

type MiddleWareFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)

func (h MiddleWareFunc) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	h(rw, r, next)
}

//中间件列表结构
//适配器模式
type middlewareHandler struct {
	handler MiddleWare
	next    *middlewareHandler
}

func (m *middlewareHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	if nil == m.handler {
		return
	}
	m.handler.ServeHTTP(rw, r, m.next.ServeHTTP)
}

//包装标准库的http.Handler
func Wrap(handler http.Handler) MiddleWare {
	return MiddleWareFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
		handler.ServeHTTP(rw, r)
		next(rw, r)
	})
}

//Cbping是一堆中间件处理程序管理器，
//可以当作http.handler被调用
//通过RegisterMiddlewareHandleFunc|RegisterMiddleWare注册中间件
type Cbping struct {
	//链表头
	//由中间件和路由处理器组建而成
	//路由处理器处于链表末端（除了末尾的空中间件）
	middlewareHead middlewareHandler
	//中间件数组
	middlewares []MiddleWare

	//路由处理器
	//原始路由处理器
	mux http.Handler
}

func (c *Cbping) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	//解析参数
	r.ParseForm()
	//中间件处理
	c.middlewareHead.ServeHTTP(rw, r)
}

//引导初始
func (c *Cbping) Bootstrap() {
	if nil == c.mux {
		c.mux = http.DefaultServeMux
	}
	c.middlewares = append(c.middlewares, Wrap(c.mux))
	c.middlewareHead = build(c.middlewares)
}

//运行
func (c *Cbping) Run(addr string) {
	c.Bootstrap()
	http.ListenAndServe(addr, c)
}

func (c *Cbping) RegisterMiddlewareHandleFunc(handlers ...func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)) {
	for _, handler := range handlers {
		c.RegisterMiddleWare(MiddleWareFunc(handler))
	}

}

//注册中间件
//中间件执行顺序和注册顺序一致
func (c *Cbping) RegisterMiddleWare(handler MiddleWare) {
	c.middlewares = append(c.middlewares, handler)
}

//注册原本路由处理器
func (c *Cbping) MuxHandler(muxHandler http.Handler) {
	c.mux = muxHandler
}

func New() *Cbping {
	return &Cbping{}
}

//递归构建执行链表
func build(handlers []MiddleWare) middlewareHandler {
	var next middlewareHandler

	if len(handlers) == 0 {
		return voidMiddlewareHandler()
	} else if len(handlers) > 1 {
		next = build(handlers[1:])
	} else {
		next = voidMiddlewareHandler()
	}

	return middlewareHandler{handlers[0], &next}
}

func voidMiddlewareHandler() middlewareHandler {
	return middlewareHandler{
		MiddleWareFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {}),
		&middlewareHandler{},
	}
}
<|endoftext|>