<commit_before>package gorm

import (
	"context"
	"database/sql"
	"database/sql/driver"
	"fmt"
	"os"
	"reflect"
	"strconv"
	"strings"

	"github.com/acidlemon/aqua"
	"github.com/jinzhu/gorm"
)

type db struct {
	root    *gorm.DB
	session *gorm.DB
}

func init() {
	aqua.RegisterProvider("gorm", Open)
}

func Open(driver, path string) (aqua.DB, error) {
	d, err := gorm.Open(driver, path)
	if err != nil {
		return nil, err
	}

	envval := os.Getenv("AQUA_DEBUG")
	val, err := strconv.Atoi(envval)
	if err == nil && val != 0 {
		d.LogMode(true)
	}

	envval = os.Getenv("AQUA_GORM_DISABLE_AUTO_TIMESTAMP")
	val, err = strconv.Atoi(envval)
	if err == nil && val != 0 {
		d.Callback().Create().Remove("gorm:update_time_stamp")
		d.Callback().Update().Remove("gorm:update_time_stamp")
	}

	return &db{root: d}, nil
}

func (db *db) GetProvider() interface{} {
	return db.root
}

func (_db *db) Begin(ctx context.Context, opts *sql.TxOptions) (aqua.Tx, error) {
	tx := _db.root.Begin()
	result := &db{
		root: tx,
	}

	return result, nil
}

func (db *db) Commit() error {
	db.root.Commit()
	errs := db.root.GetErrors()
	if len(errs) > 0 {
		return errs[0]
	}
	return nil
}
func (db *db) Rollback() error {
	db.root.Rollback()
	errs := db.root.GetErrors()
	if len(errs) > 0 {
		return errs[0]
	}
	return nil
}

func (db *db) Close() error {
	return db.root.Close()
}

func (db *db) Driver() driver.Driver {
	return db.root.DB().Driver()
}

func (db *db) Ping(ctx context.Context) error {
	return db.root.DB().PingContext(ctx)
}

func (db *db) SetMaxIdleConns(conn int) {
	db.root.DB().SetMaxIdleConns(conn)
}

func (db *db) SetMaxOpenConns(conn int) {
	db.root.DB().SetMaxOpenConns(conn)
}

func (db *db) Table(name string) aqua.StmtTable {
	db.session = db.root.Table(name)
	return db
}

func (db *db) Exec(ctx context.Context, query string, args ...interface{}) (sql.Result, error) {
	return db.root.CommonDB().Exec(query, args...)
}

func (db *db) Create(ctx context.Context, param ...interface{}) error {
	// TODO waiting support bulk insert
	for _, v := range param {
		db.session = db.session.Create(v)
	}
	return nil
}
func (db *db) Update(ctx context.Context, param interface{}) error {
	v := reflect.ValueOf(param)
	if v.Kind() == reflect.Map {
		db.session = db.session.Updates(param)
	} else {
		// TODO update using existing structパターンで
		// SET id=? WHERE id=?なクエリがでて気持ち悪いのをどうにかしたい
		db.session = db.session.Model(param).Update(param)
	}

	errs := db.session.GetErrors()
	if len(errs) > 0 {
		return errs[0]
	}
	return nil
}
func (db *db) Delete(ctx context.Context, param interface{}) error {
	db.session.Delete(param)
	return nil
}

func (db *db) Join(table, condition string) aqua.StmtTable {
	db.session = db.session.Joins(fmt.Sprintf("INNER JOIN %s ON %s", table, condition))
	return db
}

func (db *db) LeftJoin(table, condition string) aqua.StmtTable {
	db.session = db.session.Joins(fmt.Sprintf("LEFT JOIN %s ON %s", table, condition))
	return db
}

func (db *db) RightJoin(table, condition string) aqua.StmtTable {
	db.session = db.session.Joins(fmt.Sprintf("RIGHT JOIN %s ON %s", table, condition))
	return db
}

func (db *db) Select(columns ...string) aqua.StmtTable {
	db.session = db.session.Select(strings.Join(columns, ", "))
	return db
}

func (db *db) Where(condition string, bind ...interface{}) aqua.StmtCondition {
	if len(bind) == 1 {
		t := reflect.TypeOf(bind[0])
		//pp.Print(t)
		if t.Kind() == reflect.Slice {
			db.session = db.session.Where(condition, bind[0].([]interface{})...)
		} else {
			db.session = db.session.Where(condition, bind)
		}
	} else {
		db.session = db.session.Where(condition, bind...)
	}

	return db
}

func (db *db) WhereEq(column string, value interface{}) aqua.StmtCondition {
	if value == nil {
		db.session = db.session.Where(fmt.Sprintf("%s IS NULL", column))
	} else {
		db.session = db.session.Where(fmt.Sprintf("%s = ?", column), value)
	}
	return db
}

func (db *db) WhereIn(column string, values ...interface{}) aqua.StmtCondition {
	if len(values) == 1 {
		db.session = db.session.Where(fmt.Sprintf("%s in (?)", column), values...)
	} else {
		db.session = db.session.Where(fmt.Sprintf("%s in (?)", column), values)
	}
	return db
}

func (db *db) WhereBetween(column string, a, b interface{}) aqua.StmtCondition {
	db.session = db.session.Where(fmt.Sprintf("%s between ? and ?", column), a, b)
	return db
}

func (db *db) WhereLike(column, pattern string) aqua.StmtCondition {
	db.session = db.session.Where(fmt.Sprintf("%s like ?", column), pattern)
	return db
}

func (db *db) All(ctx context.Context) (aqua.Rows, error) {
	rs := &rows{
		db: db,
	}
	return rs, nil
}

func (db *db) Count(ctx context.Context) (int, error) {
	var cnt int
	db.session.Count(&cnt)
	if errs := db.session.GetErrors(); len(errs) != 0 {
		return 0, errs[len(errs)-1]
	}

	return cnt, nil
}

func (db *db) FetchColumn(ctx context.Context, column string) (aqua.Rows, error) {
	db.session = db.session.Select(column)

	rs := &rows{
		db:    db,
		pluck: true,
	}
	return rs, nil
}

func (db *db) Single(ctx context.Context) (aqua.Row, error) {
	db.session = db.session.Limit(1)

	r := &row{
		session: db.session,
	}
	return r, nil
}

func (db *db) GroupBy(groups ...string) aqua.StmtAggregate {
	db.session = db.session.Group(strings.Join(groups, ","))
	return db
}

func (db *db) OrderBy(orders ...string) aqua.StmtAggregate {
	db.session = db.session.Order(strings.Join(orders, ","))
	return db
}

func (db *db) Having(string) aqua.StmtAggregate {
	return db
}

func (db *db) LimitOffset(limit, offset int) aqua.StmtAggregate {
	return db
}
<commit_msg>disable auto timestamp at default<commit_after>package gorm

import (
	"context"
	"database/sql"
	"database/sql/driver"
	"fmt"
	"os"
	"reflect"
	"strconv"
	"strings"

	"github.com/acidlemon/aqua"
	"github.com/jinzhu/gorm"
)

type db struct {
	root    *gorm.DB
	session *gorm.DB
}

func init() {
	aqua.RegisterProvider("gorm", Open)
}

func Open(driver, path string) (aqua.DB, error) {
	d, err := gorm.Open(driver, path)
	if err != nil {
		return nil, err
	}

	envval := os.Getenv("AQUA_DEBUG")
	val, err := strconv.Atoi(envval)
	if err == nil && val != 0 {
		d.LogMode(true)
	}

	envval = os.Getenv("AQUA_GORM_ENABLE_AUTO_TIMESTAMP")
	val, err = strconv.Atoi(envval)
	if err == nil && val != 0 {

	} else {
		d.Callback().Create().Remove("gorm:update_time_stamp")
		d.Callback().Update().Remove("gorm:update_time_stamp")
	}

	return &db{root: d}, nil
}

func (db *db) GetProvider() interface{} {
	return db.root
}

func (_db *db) Begin(ctx context.Context, opts *sql.TxOptions) (aqua.Tx, error) {
	tx := _db.root.Begin()
	result := &db{
		root: tx,
	}

	return result, nil
}

func (db *db) Commit() error {
	db.root.Commit()
	errs := db.root.GetErrors()
	if len(errs) > 0 {
		return errs[0]
	}
	return nil
}
func (db *db) Rollback() error {
	db.root.Rollback()
	errs := db.root.GetErrors()
	if len(errs) > 0 {
		return errs[0]
	}
	return nil
}

func (db *db) Close() error {
	return db.root.Close()
}

func (db *db) Driver() driver.Driver {
	return db.root.DB().Driver()
}

func (db *db) Ping(ctx context.Context) error {
	return db.root.DB().PingContext(ctx)
}

func (db *db) SetMaxIdleConns(conn int) {
	db.root.DB().SetMaxIdleConns(conn)
}

func (db *db) SetMaxOpenConns(conn int) {
	db.root.DB().SetMaxOpenConns(conn)
}

func (db *db) Table(name string) aqua.StmtTable {
	db.session = db.root.Table(name)
	return db
}

func (db *db) Exec(ctx context.Context, query string, args ...interface{}) (sql.Result, error) {
	return db.root.CommonDB().Exec(query, args...)
}

func (db *db) Create(ctx context.Context, param ...interface{}) error {
	// TODO waiting support bulk insert
	for _, v := range param {
		db.session = db.session.Create(v)
	}
	return nil
}
func (db *db) Update(ctx context.Context, param interface{}) error {
	v := reflect.ValueOf(param)
	if v.Kind() == reflect.Map {
		db.session = db.session.Updates(param)
	} else {
		// TODO update using existing structパターンで
		// SET id=? WHERE id=?なクエリがでて気持ち悪いのをどうにかしたい
		db.session = db.session.Model(param).Update(param)
	}

	errs := db.session.GetErrors()
	if len(errs) > 0 {
		return errs[0]
	}
	return nil
}
func (db *db) Delete(ctx context.Context, param interface{}) error {
	db.session.Delete(param)
	return nil
}

func (db *db) Join(table, condition string) aqua.StmtTable {
	db.session = db.session.Joins(fmt.Sprintf("INNER JOIN %s ON %s", table, condition))
	return db
}

func (db *db) LeftJoin(table, condition string) aqua.StmtTable {
	db.session = db.session.Joins(fmt.Sprintf("LEFT JOIN %s ON %s", table, condition))
	return db
}

func (db *db) RightJoin(table, condition string) aqua.StmtTable {
	db.session = db.session.Joins(fmt.Sprintf("RIGHT JOIN %s ON %s", table, condition))
	return db
}

func (db *db) Select(columns ...string) aqua.StmtTable {
	db.session = db.session.Select(strings.Join(columns, ", "))
	return db
}

func (db *db) Where(condition string, bind ...interface{}) aqua.StmtCondition {
	if len(bind) == 1 {
		t := reflect.TypeOf(bind[0])
		//pp.Print(t)
		if t.Kind() == reflect.Slice {
			db.session = db.session.Where(condition, bind[0].([]interface{})...)
		} else {
			db.session = db.session.Where(condition, bind)
		}
	} else {
		db.session = db.session.Where(condition, bind...)
	}

	return db
}

func (db *db) WhereEq(column string, value interface{}) aqua.StmtCondition {
	if value == nil {
		db.session = db.session.Where(fmt.Sprintf("%s IS NULL", column))
	} else {
		db.session = db.session.Where(fmt.Sprintf("%s = ?", column), value)
	}
	return db
}

func (db *db) WhereIn(column string, values ...interface{}) aqua.StmtCondition {
	if len(values) == 1 {
		db.session = db.session.Where(fmt.Sprintf("%s in (?)", column), values...)
	} else {
		db.session = db.session.Where(fmt.Sprintf("%s in (?)", column), values)
	}
	return db
}

func (db *db) WhereBetween(column string, a, b interface{}) aqua.StmtCondition {
	db.session = db.session.Where(fmt.Sprintf("%s between ? and ?", column), a, b)
	return db
}

func (db *db) WhereLike(column, pattern string) aqua.StmtCondition {
	db.session = db.session.Where(fmt.Sprintf("%s like ?", column), pattern)
	return db
}

func (db *db) All(ctx context.Context) (aqua.Rows, error) {
	rs := &rows{
		db: db,
	}
	return rs, nil
}

func (db *db) Count(ctx context.Context) (int, error) {
	var cnt int
	db.session.Count(&cnt)
	if errs := db.session.GetErrors(); len(errs) != 0 {
		return 0, errs[len(errs)-1]
	}

	return cnt, nil
}

func (db *db) FetchColumn(ctx context.Context, column string) (aqua.Rows, error) {
	db.session = db.session.Select(column)

	rs := &rows{
		db:    db,
		pluck: true,
	}
	return rs, nil
}

func (db *db) Single(ctx context.Context) (aqua.Row, error) {
	db.session = db.session.Limit(1)

	r := &row{
		session: db.session,
	}
	return r, nil
}

func (db *db) GroupBy(groups ...string) aqua.StmtAggregate {
	db.session = db.session.Group(strings.Join(groups, ","))
	return db
}

func (db *db) OrderBy(orders ...string) aqua.StmtAggregate {
	db.session = db.session.Order(strings.Join(orders, ","))
	return db
}

func (db *db) Having(string) aqua.StmtAggregate {
	return db
}

func (db *db) LimitOffset(limit, offset int) aqua.StmtAggregate {
	return db
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/codegangsta/cli"
	"net"
	"net/smtp"
	"os"
	"strings"
	"time"
)

var (
	appName         = "gosping"
	appHelpTemplate = `
NAME:
	{{.Name}} - {{.Usage}}

USAGE:
	{{.Name}} [options] x@y.z [@server]
	Where: x@y.z  is the address that will receive e-mail
	and server is the address to connect to (optional)

VERSION:
	{{.Version}}

OPTIONS:
	{{range .Flags}}{{.}}
	{{end}}

If no @server is specified, {{.Name}} will try to find
the recipient domain's MX record, falling back on A/AAAA records.
`
)

func main() {
	cli.AppHelpTemplate = appHelpTemplate
	app := cli.NewApp()
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "debug,d",
			Usage: "Show more debugging",
		},
		cli.IntFlag{
			Name:  "port,p",
			Usage: "Which TCP port to use [default: 25]",
			Value: 25,
		},
		cli.IntFlag{
			Name:  "wait,w",
			Usage: "Time to wait between PINGs [default: 1000] (ms)",
			Value: 1000,
		},
		cli.IntFlag{
			Name:  "count,c",
			Usage: "Number on messages [default: 3]",
			Value: 3,
		},
		cli.IntFlag{
			Name:  "parallel, P",
			Usage: "Number of parallel workers [default 1]",
			Value: 1,
		},
		cli.IntFlag{
			Name:  "size,s",
			Usage: "Message size in kilobytes [default: 10] (KiB)",
			Value: 10,
		},
		cli.StringFlag{
			Name:  "file,f",
			Usage: "Send message file (RFC 822)",
			Value: "",
		},
		cli.StringFlag{
			Name:  "helo, H",
			Usage: "HELO domain [default: localhost.localdomain]",
			Value: "localhost.localdomain",
		},
		cli.StringFlag{
			Name:  "sender, S",
			Usage: "sender; Sender address [default: empty]",
			Value: "",
		},
		cli.BoolFlag{
			Name:  "rate,r",
			Usage: "rate; Show message rate per second",
		},
		cli.BoolTFlag{
			Name:  "quiet,q",
			Usage: "quiet; Show less output",
		},
		cli.BoolFlag{
			Name:  "J",
			Usage: "Run in jailed mode (forbid --file)",
		},
	}
	app.Name = "gosping"
	app.Version = "0.0.1"
	app.Usage = "Get some SMTP statistics"
	app.Action = run
	app.Run(os.Args)
}

func run(c *cli.Context) {
	var mxServer string
	var targetAddress string
	var ok bool
	targetAddress, mxServer, ok = getdestination(c)
	if ok != true {
		fmt.Printf("Error %s occured \n", ok)
	} else {
		fmt.Printf("Address is %s , server is %s \n", targetAddress, mxServer)
	}
}

func getdestination(c *cli.Context) (string, string, bool) {
	var mxServer string
	var targetAddress string
	var ok bool
	myArgs := c.Args()
	if len(myArgs) > 1 {
		if myArgs[1][:1] != "@" {
			mxServer = ""
			targetAddress = ""
			ok = false
		} else {
			mxServer = myArgs[1][1:]
			targetAddress = myArgs[0]
			ok = true
		}
	} else {
		targetAddress = myArgs[0]
		var err error
		mxServer, err = resolvmx(strings.SplitAfter(targetAddress, "@")[1])
		if err != nil {
			mxServer = ""
			ok = false
		}
		ok = true
	}
	return targetAddress, mxServer, ok
}

func connect(target string) (string, int64) {
	str := "Connect to " + target
	begin := time.Now().UnixNano()
	_, err := smtp.Dial(target + ":25")
	if err != nil {
		panic(err)
	}
	nanoduration := time.Now().UnixNano() - begin
	return str, nanoduration
}
func resolvmx(target string) (string, error) {
	mxRecord, err := net.LookupMX(target)
	return mxRecord[0].Host, err
}
<commit_msg>cleaned source, made connect return a smtp client and obey port flag.<commit_after>package main

import (
	"fmt"
	"github.com/codegangsta/cli"
	"net"
	"net/smtp"
	"os"
	"strconv"
	"strings"
	"time"
)

var (
	appName         = "gosping"
	appHelpTemplate = `
NAME:
	{{.Name}} - {{.Usage}}

USAGE:
	{{.Name}} [options] x@y.z [@server]
	Where: x@y.z  is the address that will receive e-mail
	and server is the address to connect to (optional)

VERSION:
	{{.Version}}

OPTIONS:
	{{range .Flags}}{{.}}
	{{end}}

If no @server is specified, {{.Name}} will try to find
the recipient domain's MX record, falling back on A/AAAA records.
`
)

func main() {
	cli.AppHelpTemplate = appHelpTemplate
	app := cli.NewApp()
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "debug,d",
			Usage: "Show more debugging",
		},
		cli.IntFlag{
			Name:  "port,p",
			Usage: "Which TCP port to use [default: 25]",
			Value: 25,
		},
		cli.IntFlag{
			Name:  "wait,w",
			Usage: "Time to wait between PINGs [default: 1000] (ms)",
			Value: 1000,
		},
		cli.IntFlag{
			Name:  "count,c",
			Usage: "Number on messages [default: 3]",
			Value: 3,
		},
		cli.IntFlag{
			Name:  "parallel, P",
			Usage: "Number of parallel workers [default 1]",
			Value: 1,
		},
		cli.IntFlag{
			Name:  "size,s",
			Usage: "Message size in kilobytes [default: 10] (KiB)",
			Value: 10,
		},
		cli.StringFlag{
			Name:  "file,f",
			Usage: "Send message file (RFC 822)",
			Value: "",
		},
		cli.StringFlag{
			Name:  "helo, H",
			Usage: "HELO domain [default: localhost.localdomain]",
			Value: "localhost.localdomain",
		},
		cli.StringFlag{
			Name:  "sender, S",
			Usage: "sender; Sender address [default: empty]",
			Value: "",
		},
		cli.BoolFlag{
			Name:  "rate,r",
			Usage: "rate; Show message rate per second",
		},
		cli.BoolTFlag{
			Name:  "quiet,q",
			Usage: "quiet; Show less output",
		},
		cli.BoolFlag{
			Name:  "J",
			Usage: "Run in jailed mode (forbid --file)",
		},
	}
	app.Name = "gosping"
	app.Version = "0.0.1"
	app.Usage = "Get some SMTP statistics"
	app.Action = run
	app.Run(os.Args)
}

func run(c *cli.Context) {
	targetAddress, mxServer, ok := getdestination(c)
	if ok != true {
		fmt.Printf("Error %s occured \n", ok)
	} else {
		fmt.Printf("Address is %s , server is %s \n", targetAddress, mxServer)
	}
	connecttarget := mxServer + ":" + strconv.Itoa(c.Int("port"))
	fmt.Println(connecttarget)
	_, _, err := connect(connecttarget)
	if err != nil {
		fmt.Println("Outch!")
	} else {
		fmt.Println("Success.")
	}
}

func getdestination(c *cli.Context) (string, string, bool) {
	var mxServer string
	var targetAddress string
	var ok bool
	myArgs := c.Args()
	if len(myArgs) > 1 {
		if myArgs[1][:1] != "@" {
			mxServer = ""
			targetAddress = ""
			ok = false
		} else {
			mxServer = myArgs[1][1:]
			targetAddress = myArgs[0]
			ok = true
		}
	} else {
		targetAddress = myArgs[0]
		var err error
		mxServer, err = resolvmx(strings.SplitAfter(targetAddress, "@")[1])
		if err != nil {
			mxServer = ""
			ok = false
		}
		ok = true
	}
	return targetAddress, mxServer, ok
}

func connect(target string) (*smtp.Client, int64, error) {
	begin := time.Now().UnixNano()
	client, err := smtp.Dial(target)
	nanoduration := time.Now().UnixNano() - begin
	return client, nanoduration, err
}
func resolvmx(target string) (string, error) {
	mxRecord, err := net.LookupMX(target)
	return mxRecord[0].Host, err
}
<|endoftext|>


<commit_before>package gotests

import (
	"fmt"
	"go/importer"
	"go/types"
	"path"
	"regexp"
	"sort"
	"sync"

	"github.com/cweill/gotests/internal/goparser"
	"github.com/cweill/gotests/internal/input"
	"github.com/cweill/gotests/internal/models"
	"github.com/cweill/gotests/internal/output"
)

type Options struct {
	Only        *regexp.Regexp
	Exclude     *regexp.Regexp
	Exported    bool
	PrintInputs bool
	Importer    func() types.Importer
}

type GeneratedTest struct {
	Path      string             // The test file's absolute path.
	Functions []*models.Function // The functions with new test methods.
	Output    []byte             // The contents of the test file.
}

func GenerateTests(srcPath string, opt *Options) ([]*GeneratedTest, error) {
	srcFiles, err := input.Files(srcPath)
	if err != nil {
		return nil, fmt.Errorf("input.Files: %v", err)
	}
	files, err := input.Files(path.Dir(srcPath))
	if err != nil {
		return nil, fmt.Errorf("input.Files: %v", err)
	}
	if opt.Importer == nil || opt.Importer() == nil {
		opt.Importer = importer.Default
	}
	return parallelize(srcFiles, files, opt)
}

// result stores a generateTest result.
type result struct {
	gt  *GeneratedTest
	err error
}

// parallelize generates tests for the given source files concurrently.
func parallelize(srcFiles, files []models.Path, opt *Options) ([]*GeneratedTest, error) {
	var wg sync.WaitGroup
	rs := make(chan *result, len(srcFiles))
	for _, src := range srcFiles {
		wg.Add(1)
		// Worker
		go func(src models.Path) {
			defer wg.Done()
			r := &result{}
			r.gt, r.err = generateTest(src, files, opt)
			rs <- r
		}(src)
	}
	// Closer.
	go func() {
		wg.Wait()
		close(rs)
	}()
	return readResults(rs)
}

// readResults reads the result channel.
func readResults(rs <-chan *result) ([]*GeneratedTest, error) {
	var gts []*GeneratedTest
	for r := range rs {
		if r.err != nil {
			return nil, r.err
		}
		if r.gt != nil {
			gts = append(gts, r.gt)
		}
	}
	return gts, nil
}

func generateTest(src models.Path, files []models.Path, opt *Options) (*GeneratedTest, error) {
	p := &goparser.Parser{Importer: opt.Importer()}
	sr, err := p.Parse(string(src), files)
	if err != nil {
		return nil, fmt.Errorf("Parser.Parse source file: %v", err)
	}
	h := sr.Header
	h.Code = nil // Code is only needed from parsed test files.
	testPath := models.Path(src).TestPath()
	h, tf, err := parseTestFile(p, testPath, h)
	if err != nil {
		return nil, err
	}
	funcs := testableFuncs(sr.Funcs, opt.Only, opt.Exclude, opt.Exported, tf)
	if len(funcs) == 0 {
		return nil, nil
	}
	b, err := output.Process(h, funcs, &output.Options{
		PrintInputs: opt.PrintInputs,
	})
	if err != nil {
		return nil, fmt.Errorf("output.Process: %v", err)
	}
	return &GeneratedTest{
		Path:      testPath,
		Functions: funcs,
		Output:    b,
	}, nil
}

func parseTestFile(p *goparser.Parser, testPath string, h *models.Header) (*models.Header, []string, error) {
	if !output.IsFileExist(testPath) {
		return h, nil, nil
	}
	tr, err := p.Parse(testPath, nil)
	if err != nil {
		if err == goparser.ErrEmptyFile {
			// Overwrite empty test files.
			return h, nil, nil
		}
		return nil, nil, fmt.Errorf("Parser.Parse test file: %v", err)
	}
	var testFuncs []string
	for _, fun := range tr.Funcs {
		testFuncs = append(testFuncs, fun.Name)
	}
	tr.Header.Imports = append(tr.Header.Imports, h.Imports...)
	h = tr.Header
	return h, testFuncs, nil
}

func testableFuncs(funcs []*models.Function, only, excl *regexp.Regexp, exp bool, testFuncs []string) []*models.Function {
	sort.Strings(testFuncs)
	var fs []*models.Function
	for _, f := range funcs {
		if isTestFunction(f, testFuncs) || isExcluded(f, excl) || isUnexported(f, exp) || !isIncluded(f, only) {
			continue
		}
		fs = append(fs, f)
	}
	return fs
}

func isTestFunction(f *models.Function, testFuncs []string) bool {
	return len(testFuncs) > 0 && contains(testFuncs, f.TestName())
}

func isExcluded(f *models.Function, excl *regexp.Regexp) bool {
	return excl != nil && (excl.MatchString(f.Name) || excl.MatchString(f.FullName()))
}

func isUnexported(f *models.Function, exp bool) bool {
	return exp && !f.IsExported
}

func isIncluded(f *models.Function, only *regexp.Regexp) bool {
	return only == nil || only.MatchString(f.Name) || only.MatchString(f.FullName())
}

func contains(ss []string, s string) bool {
	if i := sort.SearchStrings(ss, s); i < len(ss) && ss[i] == s {
		return true
	}
	return false
}
<commit_msg>Add documentation to gotests package.<commit_after>// Package gotests contains the core logic for generating table-driven tests.
package gotests

import (
	"fmt"
	"go/importer"
	"go/types"
	"path"
	"regexp"
	"sort"
	"sync"

	"github.com/cweill/gotests/internal/goparser"
	"github.com/cweill/gotests/internal/input"
	"github.com/cweill/gotests/internal/models"
	"github.com/cweill/gotests/internal/output"
)

// Options provides custom filters and parameters for generating tests.
type Options struct {
	Only        *regexp.Regexp        // Includes only functions that match.
	Exclude     *regexp.Regexp        // Excludes functions that match.
	Exported    bool                  // Include only exported methods
	PrintInputs bool                  // Print function parameters in error messages
	Importer    func() types.Importer // A custom importer.
}

// A GeneratedTest contains information about a test file with generated tests.
type GeneratedTest struct {
	Path      string             // The test file's absolute path.
	Functions []*models.Function // The functions with new test methods.
	Output    []byte             // The contents of the test file.
}

// GenerateTests generates table-driven tests for the function and method
// signatures defined in the target source path file(s). The source path
// parameter can be either a Go source file or directory containing Go files.
func GenerateTests(srcPath string, opt *Options) ([]*GeneratedTest, error) {
	srcFiles, err := input.Files(srcPath)
	if err != nil {
		return nil, fmt.Errorf("input.Files: %v", err)
	}
	files, err := input.Files(path.Dir(srcPath))
	if err != nil {
		return nil, fmt.Errorf("input.Files: %v", err)
	}
	if opt.Importer == nil || opt.Importer() == nil {
		opt.Importer = importer.Default
	}
	return parallelize(srcFiles, files, opt)
}

// result stores a generateTest result.
type result struct {
	gt  *GeneratedTest
	err error
}

// parallelize generates tests for the given source files concurrently.
func parallelize(srcFiles, files []models.Path, opt *Options) ([]*GeneratedTest, error) {
	var wg sync.WaitGroup
	rs := make(chan *result, len(srcFiles))
	for _, src := range srcFiles {
		wg.Add(1)
		// Worker
		go func(src models.Path) {
			defer wg.Done()
			r := &result{}
			r.gt, r.err = generateTest(src, files, opt)
			rs <- r
		}(src)
	}
	// Closer.
	go func() {
		wg.Wait()
		close(rs)
	}()
	return readResults(rs)
}

// readResults reads the result channel.
func readResults(rs <-chan *result) ([]*GeneratedTest, error) {
	var gts []*GeneratedTest
	for r := range rs {
		if r.err != nil {
			return nil, r.err
		}
		if r.gt != nil {
			gts = append(gts, r.gt)
		}
	}
	return gts, nil
}

func generateTest(src models.Path, files []models.Path, opt *Options) (*GeneratedTest, error) {
	p := &goparser.Parser{Importer: opt.Importer()}
	sr, err := p.Parse(string(src), files)
	if err != nil {
		return nil, fmt.Errorf("Parser.Parse source file: %v", err)
	}
	h := sr.Header
	h.Code = nil // Code is only needed from parsed test files.
	testPath := models.Path(src).TestPath()
	h, tf, err := parseTestFile(p, testPath, h)
	if err != nil {
		return nil, err
	}
	funcs := testableFuncs(sr.Funcs, opt.Only, opt.Exclude, opt.Exported, tf)
	if len(funcs) == 0 {
		return nil, nil
	}
	b, err := output.Process(h, funcs, &output.Options{
		PrintInputs: opt.PrintInputs,
	})
	if err != nil {
		return nil, fmt.Errorf("output.Process: %v", err)
	}
	return &GeneratedTest{
		Path:      testPath,
		Functions: funcs,
		Output:    b,
	}, nil
}

func parseTestFile(p *goparser.Parser, testPath string, h *models.Header) (*models.Header, []string, error) {
	if !output.IsFileExist(testPath) {
		return h, nil, nil
	}
	tr, err := p.Parse(testPath, nil)
	if err != nil {
		if err == goparser.ErrEmptyFile {
			// Overwrite empty test files.
			return h, nil, nil
		}
		return nil, nil, fmt.Errorf("Parser.Parse test file: %v", err)
	}
	var testFuncs []string
	for _, fun := range tr.Funcs {
		testFuncs = append(testFuncs, fun.Name)
	}
	tr.Header.Imports = append(tr.Header.Imports, h.Imports...)
	h = tr.Header
	return h, testFuncs, nil
}

func testableFuncs(funcs []*models.Function, only, excl *regexp.Regexp, exp bool, testFuncs []string) []*models.Function {
	sort.Strings(testFuncs)
	var fs []*models.Function
	for _, f := range funcs {
		if isTestFunction(f, testFuncs) || isExcluded(f, excl) || isUnexported(f, exp) || !isIncluded(f, only) {
			continue
		}
		fs = append(fs, f)
	}
	return fs
}

func isTestFunction(f *models.Function, testFuncs []string) bool {
	return len(testFuncs) > 0 && contains(testFuncs, f.TestName())
}

func isExcluded(f *models.Function, excl *regexp.Regexp) bool {
	return excl != nil && (excl.MatchString(f.Name) || excl.MatchString(f.FullName()))
}

func isUnexported(f *models.Function, exp bool) bool {
	return exp && !f.IsExported
}

func isIncluded(f *models.Function, only *regexp.Regexp) bool {
	return only == nil || only.MatchString(f.Name) || only.MatchString(f.FullName())
}

func contains(ss []string, s string) bool {
	if i := sort.SearchStrings(ss, s); i < len(ss) && ss[i] == s {
		return true
	}
	return false
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"gopkg.in/fsnotify.v1"
)

type ColorLogger log.Logger

const (
	logPrefix  = "\033[33m"
	logPostfix = "\033[0m"
)

var (
	watchedRun = ""
	watchedFmt = "."
	noRun      = flag.Bool("n", false, "only run gofmt")
	inFile     = flag.String("in", "", "input file")
	delay      = flag.Int("d", 1, "delay time before detecting file change")
	isPipe     = false
	exitCode   = 0
	lastReport = make(map[string]time.Time)
)

func getPackageNameAndImport(sourceName string) (packageName string, imports []string) {
	fset := token.NewFileSet() // positions are relative to fset

	// Parse the file containing this very example
	// but stop after processing the imports.
	f, err := parser.ParseFile(fset, sourceName, nil, parser.ImportsOnly)
	if err != nil {
		fmt.Println(err)
		return
	}

	// Print the imports from the file's AST.
	packageName = f.Name.Name

	for _, s := range f.Imports {
		importedPackageName := s.Path.Value[1 : len(s.Path.Value)-1]
		imports = append(imports, importedPackageName)
	}

	return
}

func isGoFile(f os.FileInfo) bool {
	// ignore non-Go files
	name := f.Name()
	return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
}

func isMainPackage(sourceName string) bool {
	fset := token.NewFileSet()
	f, _ := parser.ParseFile(fset, sourceName, nil, parser.ImportsOnly)

	return f.Name.Name == "main"
}

func isMainFile(sourceName string) bool {
	fset := token.NewFileSet()

	f, err := parser.ParseFile(fset, sourceName, nil, 0)
	if err != nil {
		return false
	}

	if o := f.Scope.Lookup("main"); f.Name.Name == "main" && o != nil && o.Kind == ast.Fun {
		return true
	}

	return false
}

func visitFile(path string, info os.FileInfo, err error) error {
	log.Println(info.Name())
	if isGoFile(info) {
		format(path)
		if isMainFile(path) {
			fmt.Println("main file -", path)
		}
	}
	return nil
}

func format(path string) error {
	log.Println("gofmt -w", path, logPostfix)
	command := exec.Command("gofmt", "-w", path)
	command.Stdout = os.Stdout
	command.Stderr = os.Stderr
	command.Run()
	return nil
}

func goFiles(path string) (goFiles, mainFiles []string) {
	filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
		if isGoFile(info) {
			goFiles = append(goFiles, path)
			if isMainFile(path) {
				mainFiles = append(mainFiles, path)
			}
		}
		return nil
	})
	return
}

var runCmd *exec.Cmd

func goRun(sourceName string) {
	if runCmd != nil && runCmd.Process != nil {
		runCmd.Process.Kill()
	}

	runCmd = exec.Command("go", "run", sourceName)
	go func(runCmd *exec.Cmd) {
		if len(*inFile) > 0 {
			f, err := os.Open(*inFile)
			if err != nil {
				runCmd.Stdin = os.Stdin
			} else {
				runCmd.Stdin = f
				defer f.Close()
			}
			runCmd.Stdin = f
		} else {
			runCmd.Stdin = os.Stdin
		}
		runCmd.Stdout = os.Stdout
		runCmd.Stderr = os.Stderr
		log.Println("go run", watchedRun, logPostfix)
		runCmd.Run()
		log.Println("exit", watchedRun, logPostfix)
	}(runCmd)
}

func main() {
	gowatchMain()
	os.Exit(exitCode)
}

func gowatchMain() {
	flag.Parse()

	log.SetPrefix(logPrefix)

	path, err := filepath.Abs(watchedFmt)
	if err != nil {
		panic(err)
	}

	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		panic(err)
	}

	err = watcher.Add(path)
	if err != nil {
		panic(err)
	}
	defer watcher.Close()

	goFiles, mainFiles := goFiles(path)

	// pre run gofmt on found Go files
	for _, f := range goFiles {
		format(f)
	}

	if len(mainFiles) == 1 {
		watchedRun = mainFiles[0]
		log.Println("found a main Go file, watch and run", mainFiles[0], logPostfix)
	} else if len(mainFiles) > 1 {
		watchedRun = mainFiles[0]
		log.Println("found more than one main Go files, watch and run", mainFiles[0], logPostfix)
	} else {
		log.Println("main Go files not found", logPostfix)
	}

	if len(watchedRun) > 0 && !*noRun {
		goRun(watchedRun)
	}

	log.Println("watching", path, logPostfix)

	fi, _ := os.Stdout.Stat()
	isPipe = fi.Mode()&os.ModeNamedPipe != 0

	for event := range watcher.Events {
		if event.Op == fsnotify.Create || event.Op == fsnotify.Write {
			if time.Since(lastReport[event.Name]) < time.Duration(*delay)*time.Second {
				continue
			}
			lastReport[event.Name] = time.Now()
			relPath, _ := filepath.Rel(path, event.Name)
			if isPipe {
				io.WriteString(os.Stdout, relPath+"\n")
			} else {
				if f, _ := os.Stat(event.Name); isGoFile(f) {
					format(event.Name)
					if event.Name == watchedRun && !*noRun {
						goRun(watchedRun)
					}
				}
			}
		}
	}
}
<commit_msg>Remove color logging<commit_after>package main

import (
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"gopkg.in/fsnotify.v1"
)

var (
	watchedRun = ""
	watchedFmt = "."
	noRun      = flag.Bool("n", false, "only run gofmt")
	inFile     = flag.String("in", "", "input file")

	delay      = flag.Int("d", 1, "delay time before detecting file change")
	isPipe     = false
	exitCode   = 0
	lastReport = make(map[string]time.Time)
)

func getPackageNameAndImport(sourceName string) (packageName string, imports []string) {
	fset := token.NewFileSet() // positions are relative to fset

	// Parse the file containing this very example
	// but stop after processing the imports.
	f, err := parser.ParseFile(fset, sourceName, nil, parser.ImportsOnly)
	if err != nil {
		fmt.Println(err)
		return
	}

	// Print the imports from the file's AST.
	packageName = f.Name.Name

	for _, s := range f.Imports {
		importedPackageName := s.Path.Value[1 : len(s.Path.Value)-1]
		imports = append(imports, importedPackageName)
	}

	return
}

func isGoFile(f os.FileInfo) bool {
	// ignore non-Go files
	name := f.Name()
	return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
}

func isMainPackage(sourceName string) bool {
	fset := token.NewFileSet()
	f, _ := parser.ParseFile(fset, sourceName, nil, parser.ImportsOnly)

	return f.Name.Name == "main"
}

func isMainFile(sourceName string) bool {
	fset := token.NewFileSet()

	f, err := parser.ParseFile(fset, sourceName, nil, 0)
	if err != nil {
		return false
	}

	if o := f.Scope.Lookup("main"); f.Name.Name == "main" && o != nil && o.Kind == ast.Fun {
		return true
	}

	return false
}

func visitFile(path string, info os.FileInfo, err error) error {
	log.Println(info.Name())
	if isGoFile(info) {
		format(path)
		if isMainFile(path) {
			fmt.Println("main file -", path)
		}
	}
	return nil
}

func format(path string) error {
	log.Println("gofmt -w", path)
	command := exec.Command("gofmt", "-w", path)
	command.Stdout = os.Stdout
	command.Stderr = os.Stderr
	command.Run()
	return nil
}

func goFiles(path string) (goFiles, mainFiles []string) {
	filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
		if isGoFile(info) {
			goFiles = append(goFiles, path)
			if isMainFile(path) {
				mainFiles = append(mainFiles, path)
			}
		}
		return nil
	})
	return
}

var runCmd *exec.Cmd

func goRun(sourceName string) {
	if runCmd != nil && runCmd.Process != nil {
		runCmd.Process.Kill()
	}

	runCmd = exec.Command("go", "run", sourceName)
	go func(runCmd *exec.Cmd) {
		if len(*inFile) > 0 {
			f, err := os.Open(*inFile)
			if err != nil {
				runCmd.Stdin = os.Stdin
			} else {
				runCmd.Stdin = f
				defer f.Close()
			}
		} else {
			runCmd.Stdin = os.Stdin
		}
		runCmd.Stdout = os.Stdout
		runCmd.Stderr = os.Stderr
		log.Println("go run", watchedRun)
		runCmd.Run()
		log.Println("exit", watchedRun)
	}(runCmd)
}

func main() {
	gowatchMain()
	os.Exit(exitCode)
}

func gowatchMain() {
	flag.Parse()

	path, err := filepath.Abs(watchedFmt)
	if err != nil {
		panic(err)
	}

	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		panic(err)
	}

	err = watcher.Add(path)
	if err != nil {
		panic(err)
	}
	defer watcher.Close()

	goFiles, mainFiles := goFiles(path)

	// pre run gofmt on found Go files
	for _, f := range goFiles {
		format(f)
	}

	if len(mainFiles) == 1 {
		watchedRun = mainFiles[0]
		log.Println("found a main Go file, watch and run", mainFiles[0])
	} else if len(mainFiles) > 1 {
		watchedRun = mainFiles[0]
		log.Println("found more than one main Go files, watch and run", mainFiles[0])
	} else {
		log.Println("main Go files not found")
	}

	if len(watchedRun) > 0 && !*noRun {
		goRun(watchedRun)
	}

	log.Println("watching", path)

	fi, _ := os.Stdout.Stat()
	isPipe = fi.Mode()&os.ModeNamedPipe != 0

	for event := range watcher.Events {
		if event.Op == fsnotify.Create || event.Op == fsnotify.Write {
			if time.Since(lastReport[event.Name]) < time.Duration(*delay)*time.Second {
				continue
			}
			lastReport[event.Name] = time.Now()
			relPath, _ := filepath.Rel(path, event.Name)
			if isPipe {
				io.WriteString(os.Stdout, relPath+"\n")
			} else {
				if f, _ := os.Stat(event.Name); isGoFile(f) {
					format(event.Name)
					if event.Name == watchedRun && !*noRun {
						goRun(watchedRun)
					}
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"go/parser"
	"go/token"
	"os"
	"os/exec"
	"path/filepath"

	"gopkg.in/fsnotify.v1"
)

var (
	watchPath = "."
	noRun     = flag.Bool("n", false, "only run gofmt")
)

func getPackageNameAndImport(sourceName string) (packageName string, imports []string) {
	fset := token.NewFileSet() // positions are relative to fset

	// Parse the file containing this very example
	// but stop after processing the imports.
	f, err := parser.ParseFile(fset, sourceName, nil, parser.ImportsOnly)
	if err != nil {
		fmt.Println(err)
		return
	}

	// Print the imports from the file's AST.
	packageName = f.Name.Name

	for _, s := range f.Imports {
		importedPackageName := s.Path.Value[1 : len(s.Path.Value)-1]
		imports = append(imports, importedPackageName)
	}

	return
}

func log(a ...interface{}) {
	var b []interface{}
	b = append(b, "\033[33mgowatch:")
	b = append(b, a...)
	b = append(b, "\033[0m")
	fmt.Fprintln(os.Stderr, b...)
}

func main() {
	flag.Parse()

	if flag.NArg() > 0 {
		watchPath = flag.Arg(0)
	}

	path, err := filepath.Abs(watchPath)
	if err != nil {
		panic(err)
	}

	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		panic(err)
	}

	err = watcher.Add(path)
	if err != nil {
		panic(err)
	}
	defer watcher.Close()

	log("watching", path)

	command := exec.Command("gofmt", "-w", path)
	command.Run()

	for event := range watcher.Events {
		if event.Op == fsnotify.Create || event.Op == fsnotify.Write {
			relPath, _ := filepath.Rel(path, event.Name)
			log("gofmt", relPath)
			if filepath.Ext(event.Name) == ".go" {
				command := exec.Command("gofmt", "-w", event.Name)
				command.Run()

				if packageName, _ := getPackageNameAndImport(event.Name); packageName == "main" && !*noRun {
					log("run", relPath)
					command = exec.Command("go", "run", event.Name)
					command.Stdout = os.Stdout
					command.Run()
				}
			}
		}
	}
}
<commit_msg>Allow delay processing file change for certain duration<commit_after>package main

import (
	"flag"
	"fmt"
	"go/parser"
	"go/token"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"time"

	"gopkg.in/fsnotify.v1"
)

var (
	watchPath  = "."
	noRun      = flag.Bool("n", false, "only run gofmt")
	delay      = flag.Int("d", 1, "delay time before detecting file change")
	isPipe     = false
	exitCode   = 0
	lastReport = make(map[string]time.Time)
)

// func isMainPackage(f os.File) Bool {

// }

// func hasMainFunction(f os.File) Bool {

// }

func getPackageNameAndImport(sourceName string) (packageName string, imports []string) {
	fset := token.NewFileSet() // positions are relative to fset

	// Parse the file containing this very example
	// but stop after processing the imports.
	f, err := parser.ParseFile(fset, sourceName, nil, parser.ImportsOnly)
	if err != nil {
		fmt.Println(err)
		return
	}

	// Print the imports from the file's AST.
	packageName = f.Name.Name

	for _, s := range f.Imports {
		importedPackageName := s.Path.Value[1 : len(s.Path.Value)-1]
		imports = append(imports, importedPackageName)
	}

	return
}

// func isGoFile(f os.FileInfo) bool {
// 	// ignore non-Go files
// 	name := f.Name()
// 	return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
// }

func log(a ...interface{}) {
	var b []interface{}
	b = append(b, "\033[33mgowatch:")
	b = append(b, a...)
	b = append(b, "\033[0m")
	fmt.Fprintln(os.Stderr, b...)
}

func main() {
	gowatchMain()
	os.Exit(exitCode)
}

func gowatchMain() {
	flag.Parse()

	if flag.NArg() > 0 {
		watchPath = flag.Arg(0)
	}

	path, err := filepath.Abs(watchPath)
	if err != nil {
		panic(err)
	}

	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		panic(err)
	}

	err = watcher.Add(path)
	if err != nil {
		panic(err)
	}
	defer watcher.Close()

	log("watching", path)

	command := exec.Command("gofmt", "-w", path)
	command.Run()

	fi, _ := os.Stdout.Stat()
	isPipe = fi.Mode()&os.ModeNamedPipe != 0

	for event := range watcher.Events {
		if event.Op == fsnotify.Create || event.Op == fsnotify.Write {
			if time.Since(lastReport[event.Name]) < time.Duration(*delay)*time.Second {
				continue
			}
			lastReport[event.Name] = time.Now()
			relPath, _ := filepath.Rel(path, event.Name)
			if isPipe {
				io.WriteString(os.Stdout, relPath+"\n")
			} else {
				if filepath.Ext(event.Name) == ".go" {
					log("gofmt -w", relPath)
					command := exec.Command("gofmt", "-w", event.Name)
					command.Run()
					if packageName, _ := getPackageNameAndImport(event.Name); packageName == "main" && !*noRun {
						log("run", relPath)
						command = exec.Command("go", "run", event.Name)
						command.Stdout = os.Stdout
						command.Run()
					}
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>package gpg

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"syscall"
	"time"
)

const (
	fileMode = 0600
	dirPerm  = 0700
)

func init() {
	// ensure created files don't have group or world perms set
	// this setting should be inherited by sub-processes
	syscall.Umask(077)
}

var (
	reUIDComment = regexp.MustCompile(`([^(<]+)\s+(\([^)]+\))\s+<([^>]+)>`)
	reUID        = regexp.MustCompile(`([^(<]+)\s+<([^>]+)>`)
	// GPGArgs contains the default GPG args for non-interactive use. Note: Do not use '--batch'
	// as this will disable (necessary) passphrase questions!
	GPGArgs = []string{"--quiet", "--yes", "--compress-algo=none", "--no-encrypt-to", "--no-auto-check-trustdb"}
	// Debug prints all the commands executed
	Debug = false
)

// KeyList is a searchable slice of Keys
type KeyList []Key

// UseableKeys returns the list of useable (valid keys)
func (kl KeyList) UseableKeys() KeyList {
	nkl := make(KeyList, 0, len(kl))
	for _, k := range kl {
		if !k.IsUseable() {
			continue
		}
		nkl = append(nkl, k)
	}
	return nkl
}

// FindKey will try to find the requested key
func (kl KeyList) FindKey(id string) (Key, error) {
	id = strings.TrimPrefix(id, "0x")
	for _, k := range kl {
		if k.Fingerprint == id {
			return k, nil
		}
		if strings.HasSuffix(k.Fingerprint, id) {
			return k, nil
		}
		for _, ident := range k.Identities {
			if ident.String() == id {
				return k, nil
			}
			if ident.Email == id {
				return k, nil
			}
		}
		for sk := range k.SubKeys {
			if strings.HasSuffix(sk, id) {
				return k, nil
			}
		}
	}
	return Key{}, fmt.Errorf("No matching key found")
}

// ParseColons parses the `--with-colons` output format of GPG
func ParseColons(reader io.Reader) KeyList {
	kl := make(KeyList, 0, 100)

	scanner := bufio.NewScanner(reader)

	// http://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob_plain;f=doc/DETAILS
	// Fields:
	// 0 - Type of record
	//     Types:
	//     pub - Public Key
	//     crt - X.509 cert
	//     crs - X.509 cert and private key
	//     sub - Subkey (Secondary Key)
	//     sec - Secret / Private Key
	//     ssb - Secret Subkey
	//     uid - User ID
	//     uat - User attribute
	//     sig - Signature
	//     rev - Revocation Signature
	//     fpr - Fingerprint (field 9)
	//     pkd - Public Key Data
	//     grp - Keygrip
	//     rvk - Revocation KEy
	//     tfs - TOFU stats
	//     tru - Trust database info
	//     spk - Signature subpacket
	//     cfg - Configuration data
	// 1 - Validity
	// 2 - Key length
	// 3 - Public Key Algo
	// 4 - KeyID
	// 5 - Creation Date (UTC)
	// 6 - Expiration Date
	// 7 - Cert S/N
	// 8 - Ownertrust
	// 9 - User-ID
	// 10 - Sign. Class
	// 11 - Key Caps.
	// 12 - Issuer cert fp
	// 13 - Flag
	// 14 - S/N of a token
	// 15 - Hash algo (2 - SHA-1, 8 - SHA-256)
	// 16 - Curve Name

	var cur Key

	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		fields := strings.Split(line, ":")

		switch fields[0] {
		case "pub":
			fallthrough
		case "sec":
			if cur.Fingerprint != "" && cur.KeyLength > 0 {
				kl = append(kl, cur)
			}
			validity := fields[1]
			if validity == "" && fields[0] == "sec" {
				validity = "u"
			}
			cur = Key{
				KeyType:        fields[0],
				Validity:       validity,
				KeyLength:      parseInt(fields[2]),
				CreationDate:   parseTS(fields[5]),
				ExpirationDate: parseTS(fields[6]),
				Ownertrust:     fields[8],
				Identities:     make(map[string]Identity, 1),
				SubKeys:        make(map[string]struct{}, 1),
			}
		case "sub":
			fallthrough
		case "ssb":
			cur.SubKeys[fields[4]] = struct{}{}
		case "fpr":
			if cur.Fingerprint == "" {
				cur.Fingerprint = fields[9]
			}
		case "uid":
			sn := fields[7]
			id := fields[9]
			ni := Identity{}
			if reUIDComment.MatchString(id) {
				if m := reUIDComment.FindStringSubmatch(id); len(m) > 3 {
					ni.Name = m[1]
					ni.Comment = strings.Trim(m[2], "()")
					ni.Email = m[3]
				}
			} else if reUID.MatchString(id) {
				if m := reUID.FindStringSubmatch(id); len(m) > 2 {
					ni.Name = m[1]
					ni.Email = m[2]
				}
			}
			cur.Identities[sn] = ni
		}
	}

	if cur.Fingerprint != "" && cur.KeyLength > 0 {
		kl = append(kl, cur)
	}

	return kl
}

// parseTS parses the passed string as an Epoch int and returns
// the time struct or the zero time struct
func parseTS(str string) time.Time {
	t := time.Time{}

	if sec, err := strconv.ParseInt(str, 10, 64); err == nil {
		t = time.Unix(sec, 0)
	}

	return t
}

// parseInt parses the passed string as an int and returns it
// or 0 on errors
func parseInt(str string) int {
	i := 0

	if iv, err := strconv.ParseInt(str, 10, 32); err == nil {
		i = int(iv)
	}

	return i
}

// Key is a GPG key (public or secret)
type Key struct {
	KeyType        string
	KeyLength      int
	Validity       string
	CreationDate   time.Time
	ExpirationDate time.Time
	Ownertrust     string
	Fingerprint    string
	Identities     map[string]Identity
	SubKeys        map[string]struct{}
}

// IsUseable returns true if GPG would assume this key is useable for encryption
func (k Key) IsUseable() bool {
	if k.ExpirationDate.Before(time.Now()) {
		return false
	}
	switch k.Validity {
	case "m":
		return true
	case "f":
		return true
	case "u":
		return true
	}
	return false
}

// String implement fmt.Stringer. This method produces output that is close to, but
// not exactly the same, as the output form GPG itself
func (k Key) String() string {
	fp := ""
	if len(k.Fingerprint) > 24 {
		fp = k.Fingerprint[24:]
	}
	out := fmt.Sprintf("%s   %dD/0x%s %s", k.KeyType, k.KeyLength, fp, k.CreationDate.Format("2006-01-02"))
	if !k.ExpirationDate.IsZero() {
		out += fmt.Sprintf(" [expires: %s]", k.ExpirationDate.Format("2006-01-02"))
	}
	out += "\n      Key fingerprint = " + k.Fingerprint
	for _, id := range k.Identities {
		out += fmt.Sprintf("\n" + id.String())
	}
	return out
}

// OneLine prints a terse representation of this key on one line (includes only
// the first identity!)
func (k Key) OneLine() string {
	id := Identity{}
	for _, i := range k.Identities {
		id = i
		break
	}
	return fmt.Sprintf("0x%s - %s", k.Fingerprint[24:], id.ID())
}

// Identity is a GPG identity, one key can have many IDs
type Identity struct {
	Name    string
	Comment string
	Email   string
}

// ID returns the GPG ID format
func (i Identity) ID() string {
	out := i.Name
	if i.Comment != "" {
		out += " (" + i.Comment + ")"
	}
	out += " <" + i.Email + ">"
	return out
}

// String implement fmt.Stringer. This method resembels the output gpg uses
// for user-ids
func (i Identity) String() string {
	return "uid                            " + i.ID()
}

// listKey lists all keys of the given type and matching the search strings
func listKeys(typ string, search ...string) (KeyList, error) {
	args := []string{"--with-colons", "--with-fingerprint", "--fixed-list-mode", "--list-" + typ + "-keys"}
	args = append(args, search...)
	cmd := exec.Command("gpg", args...)
	if Debug {
		fmt.Printf("gpg.listKeys: %s %+v\n", cmd.Path, cmd.Args)
	}
	out, err := cmd.CombinedOutput()
	if err != nil {
		if bytes.Contains(out, []byte("secret key not available")) {
			return KeyList{}, nil
		}
		return KeyList{}, err
	}

	return ParseColons(bytes.NewBuffer(out)), nil
}

// ListPublicKeys returns a parsed list of GPG public keys
func ListPublicKeys(search ...string) (KeyList, error) {
	return listKeys("public", search...)
}

// ListPrivateKeys returns a parsed list of GPG secret keys
func ListPrivateKeys(search ...string) (KeyList, error) {
	return listKeys("secret", search...)
}

// GetRecipients returns a list of recipient IDs for a given file
func GetRecipients(file string) ([]string, error) {
	_ = os.Setenv("LANGUAGE", "C")
	recp := make([]string, 0, 5)

	args := []string{"--batch", "--list-only", "--no-default-keyring", "--secret-keyring", "/dev/null", file}
	cmd := exec.Command("gpg", args...)
	if Debug {
		fmt.Printf("gpg.GetRecipients: %s %+v\n", cmd.Path, cmd.Args)
	}
	out, err := cmd.CombinedOutput()
	if err != nil {
		return []string{}, err
	}

	scanner := bufio.NewScanner(bytes.NewBuffer(out))
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if !strings.HasPrefix(line, "gpg:") {
			continue
		}
		p := strings.Split(line, ",")
		if len(p) < 2 {
			continue
		}
		p = strings.Split(strings.TrimSpace(p[1]), " ")
		if len(p) < 2 {
			continue
		}
		recp = append(recp, p[1])
	}

	return recp, nil
}

// Encrypt will encrypt the given content for the recipients. If alwaysTrust is true
// the trust-model will be set to always as to avoid (annoying) "unuseable public key"
// errors when encrypting.
func Encrypt(path string, content []byte, recipients []string, alwaysTrust bool) error {
	if err := os.MkdirAll(filepath.Dir(path), dirPerm); err != nil {
		return err
	}

	args := append(GPGArgs, "--encrypt", "--output", path)
	if alwaysTrust {
		// changing the trustmodel is possibly dangerous. A user should always
		// explicitly opt-in to do this
		args = append(args, "--trust-model=always")
	}
	for _, r := range recipients {
		args = append(args, "--recipient", r)
	}

	cmd := exec.Command("gpg", args...)
	if Debug {
		fmt.Printf("gpg.Encrypt: %s %+v\n", cmd.Path, cmd.Args)
	}
	cmd.Stdin = bytes.NewReader(content)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if err := cmd.Run(); err != nil {
		return err
	}

	return nil
}

// Decrypt will try to decrypt the given file
func Decrypt(path string) ([]byte, error) {
	args := append(GPGArgs, "--decrypt", path)
	cmd := exec.Command("gpg", args...)
	if Debug {
		fmt.Printf("gpg.Decrypt: %s %+v\n", cmd.Path, cmd.Args)
	}
	return cmd.Output()
}

// ExportPublicKey will export the named public key to the location given
func ExportPublicKey(id, filename string) error {
	args := append(GPGArgs, "--armor", "--export", id)
	cmd := exec.Command("gpg", args...)
	if Debug {
		fmt.Printf("gpg.ExportPublicKey: %s %+v\n", cmd.Path, cmd.Args)
	}
	out, err := cmd.Output()
	if err != nil {
		return err
	}

	return ioutil.WriteFile(filename, out, fileMode)
}

// ImportPublicKey will import a key from the given location
func ImportPublicKey(filename string) error {
	buf, err := ioutil.ReadFile(filename)
	if err != nil {
		return err
	}

	args := append(GPGArgs, "--import")
	cmd := exec.Command("gpg", args...)
	if Debug {
		fmt.Printf("gpg.ImportPublicKey: %s %+v\n", cmd.Path, cmd.Args)
	}
	cmd.Stdin = bytes.NewReader(buf)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	return cmd.Run()
}
<commit_msg>Use gpg2 if available<commit_after>package gpg

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"syscall"
	"time"
)

const (
	fileMode = 0600
	dirPerm  = 0700
)

func init() {
	// ensure created files don't have group or world perms set
	// this setting should be inherited by sub-processes
	syscall.Umask(077)
}

var (
	reUIDComment = regexp.MustCompile(`([^(<]+)\s+(\([^)]+\))\s+<([^>]+)>`)
	reUID        = regexp.MustCompile(`([^(<]+)\s+<([^>]+)>`)
	// GPGArgs contains the default GPG args for non-interactive use. Note: Do not use '--batch'
	// as this will disable (necessary) passphrase questions!
	GPGArgs = []string{"--quiet", "--yes", "--compress-algo=none", "--no-encrypt-to", "--no-auto-check-trustdb"}
	// Debug prints all the commands executed
	Debug = false
	// GPGBin is the name and possibly location of the gpg binary
	GPGBin = "gpg"
)

func init() {
	for _, b := range []string{"gpg2", "gpg1", "gpg"} {
		if p, err := exec.LookPath(b); err == nil {
			GPGBin = p
			break
		}
	}
}

// KeyList is a searchable slice of Keys
type KeyList []Key

// UseableKeys returns the list of useable (valid keys)
func (kl KeyList) UseableKeys() KeyList {
	nkl := make(KeyList, 0, len(kl))
	for _, k := range kl {
		if !k.IsUseable() {
			continue
		}
		nkl = append(nkl, k)
	}
	return nkl
}

// FindKey will try to find the requested key
func (kl KeyList) FindKey(id string) (Key, error) {
	id = strings.TrimPrefix(id, "0x")
	for _, k := range kl {
		if k.Fingerprint == id {
			return k, nil
		}
		if strings.HasSuffix(k.Fingerprint, id) {
			return k, nil
		}
		for _, ident := range k.Identities {
			if ident.String() == id {
				return k, nil
			}
			if ident.Email == id {
				return k, nil
			}
		}
		for sk := range k.SubKeys {
			if strings.HasSuffix(sk, id) {
				return k, nil
			}
		}
	}
	return Key{}, fmt.Errorf("No matching key found")
}

// ParseColons parses the `--with-colons` output format of GPG
func ParseColons(reader io.Reader) KeyList {
	kl := make(KeyList, 0, 100)

	scanner := bufio.NewScanner(reader)

	// http://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob_plain;f=doc/DETAILS
	// Fields:
	// 0 - Type of record
	//     Types:
	//     pub - Public Key
	//     crt - X.509 cert
	//     crs - X.509 cert and private key
	//     sub - Subkey (Secondary Key)
	//     sec - Secret / Private Key
	//     ssb - Secret Subkey
	//     uid - User ID
	//     uat - User attribute
	//     sig - Signature
	//     rev - Revocation Signature
	//     fpr - Fingerprint (field 9)
	//     pkd - Public Key Data
	//     grp - Keygrip
	//     rvk - Revocation KEy
	//     tfs - TOFU stats
	//     tru - Trust database info
	//     spk - Signature subpacket
	//     cfg - Configuration data
	// 1 - Validity
	// 2 - Key length
	// 3 - Public Key Algo
	// 4 - KeyID
	// 5 - Creation Date (UTC)
	// 6 - Expiration Date
	// 7 - Cert S/N
	// 8 - Ownertrust
	// 9 - User-ID
	// 10 - Sign. Class
	// 11 - Key Caps.
	// 12 - Issuer cert fp
	// 13 - Flag
	// 14 - S/N of a token
	// 15 - Hash algo (2 - SHA-1, 8 - SHA-256)
	// 16 - Curve Name

	var cur Key

	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		fields := strings.Split(line, ":")

		switch fields[0] {
		case "pub":
			fallthrough
		case "sec":
			if cur.Fingerprint != "" && cur.KeyLength > 0 {
				kl = append(kl, cur)
			}
			validity := fields[1]
			if validity == "" && fields[0] == "sec" {
				validity = "u"
			}
			cur = Key{
				KeyType:        fields[0],
				Validity:       validity,
				KeyLength:      parseInt(fields[2]),
				CreationDate:   parseTS(fields[5]),
				ExpirationDate: parseTS(fields[6]),
				Ownertrust:     fields[8],
				Identities:     make(map[string]Identity, 1),
				SubKeys:        make(map[string]struct{}, 1),
			}
		case "sub":
			fallthrough
		case "ssb":
			cur.SubKeys[fields[4]] = struct{}{}
		case "fpr":
			if cur.Fingerprint == "" {
				cur.Fingerprint = fields[9]
			}
		case "uid":
			sn := fields[7]
			id := fields[9]
			ni := Identity{}
			if reUIDComment.MatchString(id) {
				if m := reUIDComment.FindStringSubmatch(id); len(m) > 3 {
					ni.Name = m[1]
					ni.Comment = strings.Trim(m[2], "()")
					ni.Email = m[3]
				}
			} else if reUID.MatchString(id) {
				if m := reUID.FindStringSubmatch(id); len(m) > 2 {
					ni.Name = m[1]
					ni.Email = m[2]
				}
			}
			cur.Identities[sn] = ni
		}
	}

	if cur.Fingerprint != "" && cur.KeyLength > 0 {
		kl = append(kl, cur)
	}

	return kl
}

// parseTS parses the passed string as an Epoch int and returns
// the time struct or the zero time struct
func parseTS(str string) time.Time {
	t := time.Time{}

	if sec, err := strconv.ParseInt(str, 10, 64); err == nil {
		t = time.Unix(sec, 0)
	}

	return t
}

// parseInt parses the passed string as an int and returns it
// or 0 on errors
func parseInt(str string) int {
	i := 0

	if iv, err := strconv.ParseInt(str, 10, 32); err == nil {
		i = int(iv)
	}

	return i
}

// Key is a GPG key (public or secret)
type Key struct {
	KeyType        string
	KeyLength      int
	Validity       string
	CreationDate   time.Time
	ExpirationDate time.Time
	Ownertrust     string
	Fingerprint    string
	Identities     map[string]Identity
	SubKeys        map[string]struct{}
}

// IsUseable returns true if GPG would assume this key is useable for encryption
func (k Key) IsUseable() bool {
	if k.ExpirationDate.Before(time.Now()) {
		return false
	}
	switch k.Validity {
	case "m":
		return true
	case "f":
		return true
	case "u":
		return true
	}
	return false
}

// String implement fmt.Stringer. This method produces output that is close to, but
// not exactly the same, as the output form GPG itself
func (k Key) String() string {
	fp := ""
	if len(k.Fingerprint) > 24 {
		fp = k.Fingerprint[24:]
	}
	out := fmt.Sprintf("%s   %dD/0x%s %s", k.KeyType, k.KeyLength, fp, k.CreationDate.Format("2006-01-02"))
	if !k.ExpirationDate.IsZero() {
		out += fmt.Sprintf(" [expires: %s]", k.ExpirationDate.Format("2006-01-02"))
	}
	out += "\n      Key fingerprint = " + k.Fingerprint
	for _, id := range k.Identities {
		out += fmt.Sprintf("\n" + id.String())
	}
	return out
}

// OneLine prints a terse representation of this key on one line (includes only
// the first identity!)
func (k Key) OneLine() string {
	id := Identity{}
	for _, i := range k.Identities {
		id = i
		break
	}
	return fmt.Sprintf("0x%s - %s", k.Fingerprint[24:], id.ID())
}

// Identity is a GPG identity, one key can have many IDs
type Identity struct {
	Name    string
	Comment string
	Email   string
}

// ID returns the GPG ID format
func (i Identity) ID() string {
	out := i.Name
	if i.Comment != "" {
		out += " (" + i.Comment + ")"
	}
	out += " <" + i.Email + ">"
	return out
}

// String implement fmt.Stringer. This method resembels the output gpg uses
// for user-ids
func (i Identity) String() string {
	return "uid                            " + i.ID()
}

// listKey lists all keys of the given type and matching the search strings
func listKeys(typ string, search ...string) (KeyList, error) {
	args := []string{"--with-colons", "--with-fingerprint", "--fixed-list-mode", "--list-" + typ + "-keys"}
	args = append(args, search...)
	cmd := exec.Command(GPGBin, args...)
	if Debug {
		fmt.Printf("gpg.listKeys: %s %+v\n", cmd.Path, cmd.Args)
	}
	out, err := cmd.CombinedOutput()
	if err != nil {
		if bytes.Contains(out, []byte("secret key not available")) {
			return KeyList{}, nil
		}
		return KeyList{}, err
	}

	return ParseColons(bytes.NewBuffer(out)), nil
}

// ListPublicKeys returns a parsed list of GPG public keys
func ListPublicKeys(search ...string) (KeyList, error) {
	return listKeys("public", search...)
}

// ListPrivateKeys returns a parsed list of GPG secret keys
func ListPrivateKeys(search ...string) (KeyList, error) {
	return listKeys("secret", search...)
}

// GetRecipients returns a list of recipient IDs for a given file
func GetRecipients(file string) ([]string, error) {
	_ = os.Setenv("LANGUAGE", "C")
	recp := make([]string, 0, 5)

	args := []string{"--batch", "--list-only", "--no-default-keyring", "--secret-keyring", "/dev/null", file}
	cmd := exec.Command(GPGBin, args...)
	if Debug {
		fmt.Printf("gpg.GetRecipients: %s %+v\n", cmd.Path, cmd.Args)
	}
	out, err := cmd.CombinedOutput()
	if err != nil {
		return []string{}, err
	}

	scanner := bufio.NewScanner(bytes.NewBuffer(out))
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if !strings.HasPrefix(line, "gpg:") {
			continue
		}
		p := strings.Split(line, ",")
		if len(p) < 2 {
			continue
		}
		p = strings.Split(strings.TrimSpace(p[1]), " ")
		if len(p) < 2 {
			continue
		}
		recp = append(recp, p[1])
	}

	return recp, nil
}

// Encrypt will encrypt the given content for the recipients. If alwaysTrust is true
// the trust-model will be set to always as to avoid (annoying) "unuseable public key"
// errors when encrypting.
func Encrypt(path string, content []byte, recipients []string, alwaysTrust bool) error {
	if err := os.MkdirAll(filepath.Dir(path), dirPerm); err != nil {
		return err
	}

	args := append(GPGArgs, "--encrypt", "--output", path)
	if alwaysTrust {
		// changing the trustmodel is possibly dangerous. A user should always
		// explicitly opt-in to do this
		args = append(args, "--trust-model=always")
	}
	for _, r := range recipients {
		args = append(args, "--recipient", r)
	}

	cmd := exec.Command(GPGBin, args...)
	if Debug {
		fmt.Printf("gpg.Encrypt: %s %+v\n", cmd.Path, cmd.Args)
	}
	cmd.Stdin = bytes.NewReader(content)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if err := cmd.Run(); err != nil {
		return err
	}

	return nil
}

// Decrypt will try to decrypt the given file
func Decrypt(path string) ([]byte, error) {
	args := append(GPGArgs, "--decrypt", path)
	cmd := exec.Command(GPGBin, args...)
	if Debug {
		fmt.Printf("gpg.Decrypt: %s %+v\n", cmd.Path, cmd.Args)
	}
	return cmd.Output()
}

// ExportPublicKey will export the named public key to the location given
func ExportPublicKey(id, filename string) error {
	args := append(GPGArgs, "--armor", "--export", id)
	cmd := exec.Command(GPGBin, args...)
	if Debug {
		fmt.Printf("gpg.ExportPublicKey: %s %+v\n", cmd.Path, cmd.Args)
	}
	out, err := cmd.Output()
	if err != nil {
		return err
	}

	return ioutil.WriteFile(filename, out, fileMode)
}

// ImportPublicKey will import a key from the given location
func ImportPublicKey(filename string) error {
	buf, err := ioutil.ReadFile(filename)
	if err != nil {
		return err
	}

	args := append(GPGArgs, "--import")
	cmd := exec.Command(GPGBin, args...)
	if Debug {
		fmt.Printf("gpg.ImportPublicKey: %s %+v\n", cmd.Path, cmd.Args)
	}
	cmd.Stdin = bytes.NewReader(buf)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	return cmd.Run()
}
<|endoftext|>


<commit_before>package vm

// Module is a collection of functions
type Module struct {
	Main      *Bytecode
	Functions []*Bytecode
}
<commit_msg>redesign Module struct<commit_after>package vm

import "plaid/types"

// Module holds all the data necessary to build and evaluate a code module
// including all child closures and any dependency information
type Module struct {
	Root    *ClosureTemplate
	Exports map[string]*Export
}

// Export describes an object made available to other modules. That object is
// described by a type for use during the type-checking stage of whatever
// modules use this export
type Export struct {
	Type   types.Type
	Object Object
}
<|endoftext|>


<commit_before>package gui

import (
	"fmt"

	"github.com/drgarcia1986/gonews/story"
	"github.com/drgarcia1986/gonews/utils"
	"github.com/jroimartin/gocui"
)

var (
	downKeys = []interface{}{'j', gocui.KeyArrowDown}
	upKeys   = []interface{}{'k', gocui.KeyArrowUp}
	quitKeys = []interface{}{'q', gocui.KeyCtrlC}

	keybindingMap = []struct {
		keys     []interface{}
		viewName string
		event    func(*gocui.Gui, *gocui.View) error
	}{
		{quitKeys, "", quit},
		{downKeys, "main", cursorDown},
		{upKeys, "main", cursorUp},
		{[]interface{}{'?'}, "main", helpMsg},
	}
)

type Gui struct {
	items        []*story.Story
	providerName string
}

func (gui *Gui) getLine(g *gocui.Gui, v *gocui.View) error {
	_, cy := v.Cursor()
	line, err := v.Line(cy)
	if err != nil {
		return nil
	}

	for _, story := range gui.items {
		if story.Title == line {
			return utils.OpenURL(story.URL)
		}
	}
	return nil
}

func (gui *Gui) layout(g *gocui.Gui) error {
	maxX, maxY := g.Size()
	if v, err := g.SetView("main", 0, 0, maxX-1, maxY-1); err != nil {
		if err != gocui.ErrUnknownView {
			return err
		}
		v.Title = fmt.Sprintf("GoNews - %s ('?' for help)", gui.providerName)
		v.Highlight = true
		v.SelBgColor = gocui.ColorGreen
		v.SelFgColor = gocui.ColorBlack

		for _, story := range gui.items {
			fmt.Fprintln(v, story.Title)
		}

		if _, err := g.SetCurrentView("main"); err != nil {
			return err
		}
	}
	return nil
}

func (gui *Gui) keybindings(g *gocui.Gui) error {
	for _, bm := range keybindingMap {
		for _, key := range bm.keys {
			if err := g.SetKeybinding(bm.viewName, key, gocui.ModNone, bm.event); err != nil {
				return err
			}
		}
	}

	if err := g.SetKeybinding("main", gocui.KeyEnter, gocui.ModNone, gui.getLine); err != nil {
		return err
	}

	return nil
}

func (gui *Gui) Run() error {
	g, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		return err
	}
	defer g.Close()

	g.Cursor = true
	g.SetManagerFunc(gui.layout)
	if err := gui.keybindings(g); err != nil {
		return err
	}

	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
		return err
	}
	return nil
}

func New(items []*story.Story, providerName string) *Gui {
	guiItems := make([]*story.Story, len(items))
	copy(guiItems, items)
	return &Gui{items: guiItems, providerName: providerName}
}
<commit_msg>Disable cursor<commit_after>package gui

import (
	"fmt"

	"github.com/drgarcia1986/gonews/story"
	"github.com/drgarcia1986/gonews/utils"
	"github.com/jroimartin/gocui"
)

var (
	downKeys = []interface{}{'j', gocui.KeyArrowDown}
	upKeys   = []interface{}{'k', gocui.KeyArrowUp}
	quitKeys = []interface{}{'q', gocui.KeyCtrlC}

	keybindingMap = []struct {
		keys     []interface{}
		viewName string
		event    func(*gocui.Gui, *gocui.View) error
	}{
		{quitKeys, "", quit},
		{downKeys, "main", cursorDown},
		{upKeys, "main", cursorUp},
		{[]interface{}{'?'}, "main", helpMsg},
	}
)

type Gui struct {
	items        []*story.Story
	providerName string
}

func (gui *Gui) getLine(g *gocui.Gui, v *gocui.View) error {
	_, cy := v.Cursor()
	line, err := v.Line(cy)
	if err != nil {
		return nil
	}

	for _, story := range gui.items {
		if story.Title == line {
			return utils.OpenURL(story.URL)
		}
	}
	return nil
}

func (gui *Gui) layout(g *gocui.Gui) error {
	maxX, maxY := g.Size()
	if v, err := g.SetView("main", 0, 0, maxX-1, maxY-1); err != nil {
		if err != gocui.ErrUnknownView {
			return err
		}
		v.Title = fmt.Sprintf("GoNews - %s ('?' for help)", gui.providerName)
		v.Highlight = true
		v.SelBgColor = gocui.ColorGreen
		v.SelFgColor = gocui.ColorBlack

		for _, story := range gui.items {
			fmt.Fprintln(v, story.Title)
		}

		if _, err := g.SetCurrentView("main"); err != nil {
			return err
		}
	}
	return nil
}

func (gui *Gui) keybindings(g *gocui.Gui) error {
	for _, bm := range keybindingMap {
		for _, key := range bm.keys {
			if err := g.SetKeybinding(bm.viewName, key, gocui.ModNone, bm.event); err != nil {
				return err
			}
		}
	}

	if err := g.SetKeybinding("main", gocui.KeyEnter, gocui.ModNone, gui.getLine); err != nil {
		return err
	}

	return nil
}

func (gui *Gui) Run() error {
	g, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		return err
	}
	defer g.Close()

	g.SetManagerFunc(gui.layout)
	if err := gui.keybindings(g); err != nil {
		return err
	}

	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
		return err
	}
	return nil
}

func New(items []*story.Story, providerName string) *Gui {
	guiItems := make([]*story.Story, len(items))
	copy(guiItems, items)
	return &Gui{items: guiItems, providerName: providerName}
}
<|endoftext|>


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

package req

import (
	"flag"
	"fmt"
	"net/http"
	"testing"
	"time"
)

func init() {
	http2inTests = true
	http2DebugGoroutines = true
	flag.BoolVar(&http2VerboseLogs, "verboseh2", http2VerboseLogs, "Verbose HTTP/2 debug logging")
}

func TestSettingString(t *testing.T) {
	tests := []struct {
		s    http2Setting
		want string
	}{
		{http2Setting{http2SettingMaxFrameSize, 123}, "[MAX_FRAME_SIZE = 123]"},
		{http2Setting{1<<16 - 1, 123}, "[UNKNOWN_SETTING_65535 = 123]"},
	}
	for i, tt := range tests {
		got := fmt.Sprint(tt.s)
		if got != tt.want {
			t.Errorf("%d. for %#v, string = %q; want %q", i, tt.s, got, tt.want)
		}
	}
}

func cleanDate(res *http.Response) {
	if d := res.Header["Date"]; len(d) == 1 {
		d[0] = "XXX"
	}
}

func TestSorterPoolAllocs(t *testing.T) {
	ss := []string{"a", "b", "c"}
	h := http.Header{
		"a": nil,
		"b": nil,
		"c": nil,
	}
	sorter := new(http2sorter)

	if allocs := testing.AllocsPerRun(100, func() {
		sorter.SortStrings(ss)
	}); allocs >= 1 {
		t.Logf("SortStrings allocs = %v; want <1", allocs)
	}

	if allocs := testing.AllocsPerRun(5, func() {
		if len(sorter.Keys(h)) != 3 {
			t.Fatal("wrong result")
		}
	}); allocs > 0 {
		t.Logf("Keys allocs = %v; want <1", allocs)
	}
}

// waitCondition reports whether fn eventually returned true,
// checking immediately and then every checkEvery amount,
// until waitFor has elapsed, at which point it returns false.
func waitCondition(waitFor, checkEvery time.Duration, fn func() bool) bool {
	deadline := time.Now().Add(waitFor)
	for time.Now().Before(deadline) {
		if fn() {
			return true
		}
		time.Sleep(checkEvery)
	}
	return false
}

func TestSettingValid(t *testing.T) {
	cases := []struct {
		id  http2SettingID
		val uint32
	}{
		{
			id:  http2SettingEnablePush,
			val: 2,
		},
		{
			id:  http2SettingInitialWindowSize,
			val: 1 << 31,
		},
		{
			id:  http2SettingMaxFrameSize,
			val: 0,
		},
	}
	for _, c := range cases {
		s := &http2Setting{ID: c.id, Val: c.val}
		assertEqual(t, true, s.Valid() != nil)
	}
	s := &http2Setting{ID: http2SettingMaxHeaderListSize}
	assertEqual(t, true, s.Valid() == nil)
}
<commit_msg>add TestBodyAllowedForStatus and TestHttpError<commit_after>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package req

import (
	"flag"
	"fmt"
	"net/http"
	"testing"
	"time"
)

func init() {
	http2inTests = true
	http2DebugGoroutines = true
	flag.BoolVar(&http2VerboseLogs, "verboseh2", http2VerboseLogs, "Verbose HTTP/2 debug logging")
}

func TestSettingString(t *testing.T) {
	tests := []struct {
		s    http2Setting
		want string
	}{
		{http2Setting{http2SettingMaxFrameSize, 123}, "[MAX_FRAME_SIZE = 123]"},
		{http2Setting{1<<16 - 1, 123}, "[UNKNOWN_SETTING_65535 = 123]"},
	}
	for i, tt := range tests {
		got := fmt.Sprint(tt.s)
		if got != tt.want {
			t.Errorf("%d. for %#v, string = %q; want %q", i, tt.s, got, tt.want)
		}
	}
}

func cleanDate(res *http.Response) {
	if d := res.Header["Date"]; len(d) == 1 {
		d[0] = "XXX"
	}
}

func TestSorterPoolAllocs(t *testing.T) {
	ss := []string{"a", "b", "c"}
	h := http.Header{
		"a": nil,
		"b": nil,
		"c": nil,
	}
	sorter := new(http2sorter)

	if allocs := testing.AllocsPerRun(100, func() {
		sorter.SortStrings(ss)
	}); allocs >= 1 {
		t.Logf("SortStrings allocs = %v; want <1", allocs)
	}

	if allocs := testing.AllocsPerRun(5, func() {
		if len(sorter.Keys(h)) != 3 {
			t.Fatal("wrong result")
		}
	}); allocs > 0 {
		t.Logf("Keys allocs = %v; want <1", allocs)
	}
}

// waitCondition reports whether fn eventually returned true,
// checking immediately and then every checkEvery amount,
// until waitFor has elapsed, at which point it returns false.
func waitCondition(waitFor, checkEvery time.Duration, fn func() bool) bool {
	deadline := time.Now().Add(waitFor)
	for time.Now().Before(deadline) {
		if fn() {
			return true
		}
		time.Sleep(checkEvery)
	}
	return false
}

func TestSettingValid(t *testing.T) {
	cases := []struct {
		id  http2SettingID
		val uint32
	}{
		{
			id:  http2SettingEnablePush,
			val: 2,
		},
		{
			id:  http2SettingInitialWindowSize,
			val: 1 << 31,
		},
		{
			id:  http2SettingMaxFrameSize,
			val: 0,
		},
	}
	for _, c := range cases {
		s := &http2Setting{ID: c.id, Val: c.val}
		assertEqual(t, true, s.Valid() != nil)
	}
	s := &http2Setting{ID: http2SettingMaxHeaderListSize}
	assertEqual(t, true, s.Valid() == nil)
}

func TestBodyAllowedForStatus(t *testing.T) {
	assertEqual(t, false, http2bodyAllowedForStatus(101))
	assertEqual(t, false, http2bodyAllowedForStatus(204))
	assertEqual(t, false, http2bodyAllowedForStatus(304))
	assertEqual(t, true, http2bodyAllowedForStatus(900))
}

func TestHttpError(t *testing.T) {
	e := &http2httpError{msg: "test"}
	assertEqual(t, "test", e.Error())
	assertEqual(t, true, e.Temporary())
}
<|endoftext|>


<commit_before>package mmoa

// Monolithic Message-Oriented Application (MMOA)
// Handler
// Copyright © 2016 Eduard Sesigin. All rights reserved. Contacts: <claygod@yandex.ru>

import (
	"html/template"
	"io"
	"net/http"

	"github.com/claygod/mmoa/service"
	"github.com/claygod/mmoa/support"
	"github.com/claygod/mmoa/tools"
)

// import "fmt"

// NewHandler - create a new Handler
func NewHandler(path string, chBus chan *tools.Message, aggregator *support.Aggregator, cid *Cid) *Handler {
	h := &Handler{
		the:        tools.NewThemes(),
		cid:        cid,
		parts:      make([]*tools.HandlerPart, 0),
		chBus:      chBus,
		aggregator: aggregator,
		templates:  make(map[tools.TypeSERVICE]map[tools.TypeTHEME]*template.Template),
		view:       NewView(),
	}
	h.view.TemplatePage(path)
	return h
}

// Handler structure
type Handler struct {
	the          *tools.Themes
	cid          *Cid
	tpl          *template.Template
	parts        []*tools.HandlerPart
	chBus        chan *tools.Message
	aggregator   *support.Aggregator
	templates    map[tools.TypeSERVICE]map[tools.TypeTHEME]*template.Template
	statusCodeOf tools.TypeTHEME
	contentType  string
	view         *View
}

func (h *Handler) StatusCodeOf(theme tools.TypeTHEME) *Handler {
	h.view.StatusCodeOf(theme)
	return h
}

func (h *Handler) Service(hp *tools.HandlerPart) *Handler {
	h.view.TemplateService(hp.PartName, hp.PartTheme, hp.PartTemplate)
	h.parts = append(h.parts, hp)
	return h
}

func (h *Handler) ContentType(ct string) *Handler {
	h.view.ContentType(ct)
	return h
}

func (h *Handler) Do(w http.ResponseWriter, req *http.Request) {
	w.Header().Del("Content-Type")
	w.Header().Set("Content-Type", h.contentType)
	ch := h.handlePush(req)

	msgAgg := <-ch
	var agg *service.Aggregate
	if ag, ok := msgAgg.MsgCtx[h.the.Attach.Aggregate]; ok {
		agg = ag.(*service.Aggregate)
	} else {
		w.WriteHeader(404)
		io.WriteString(w, "404 Page not found")
		return
	}
	arr, statusCode := h.view.ProcessingAggregate(agg.Messages, msgAgg.MsgStatusCode)
	w.WriteHeader(statusCode)
	h.view.tpl.Execute(w, arr)
}

func (h *Handler) handlePush(req *http.Request) chan *tools.Message {
	a := &service.Aggregate{}
	var msg *tools.Message
	cid := h.cid.Get()
	ch := make(chan *tools.Message, len(h.parts))
	messages := make(map[string]*tools.Message)
	for _, p := range h.parts {
		key := a.GenKey(p.PartName, p.PartTheme)
		messages[key] = nil
	}
	h.aggregator.Aggregate(cid, tools.DurationHandle, messages, ch)
	for _, p := range h.parts {
		msg = tools.NewMessage().Cid(cid).
			From(h.the.Service.Controller).To(p.PartName).Re(h.the.Service.Aggregator).
			Field(h.the.Attach.Request, req).
			Theme(p.PartTheme)
		h.chBus <- msg
	}
	return ch
}
<commit_msg>Delete handler.go<commit_after><|endoftext|>


<commit_before>package logging

import (
	"bytes"
	"io"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"text/template"
	"time"
)

const (
	DefaultTimeLayout = "2006-01-02 15:04:05"
	DefaultFormat     = "[{{.TimeString}}] {{.Level}} {{.Message}}\n"
	DefaultBufSize    = 1024
)

type Handler interface {
	SetBufSize(int)
	SetLevel(LogLevel)
	SetLevelString(string)
	SetLevelRange(LogLevel, LogLevel)
	SetLevelRangeString(string, string)
	SetTimeLayout(string)
	SetFormat(string) error
	SetFilter(func(*Record) bool)
	Emit(Record)
}

type Record struct {
	Time       time.Time
	TimeString string
	Level      LogLevel
	Message    string
}

type BaseHandler struct {
	Mutex      sync.Mutex
	State      bool
	LastError  error
	Writer     io.Writer
	Level      LogLevel
	LRange     *LevelRange
	TimeLayout string
	Tmpl       *template.Template
	Buffer     chan *Record
	BufSize    int
	Filter     func(*Record) bool
	Before     func(*Record, io.ReadWriter)
	After      func(*Record, int64)
}

func NewBaseHandler(out io.Writer, level LogLevel, layout, format string) (*BaseHandler, error) {
	h := &BaseHandler{
		State:      true,
		Writer:     out,
		Level:      level,
		TimeLayout: layout,
	}
	if err := h.SetFormat(format); err != nil {
		return nil, err
	}
	h.BufSize = DefaultBufSize
	h.Buffer = make(chan *Record, h.BufSize)
	go h.notify()
	go h.WriteRecord()
	return h, nil
}

func (h *BaseHandler) SetBufSize(size int) {
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	h.BufSize = size
	h.Buffer <- nil
}

func (h *BaseHandler) SetLevel(level LogLevel) {
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	h.Level = level
}

func (h *BaseHandler) SetLevelString(s string) {
	h.SetLevel(StringToLogLevel(s))
}

func (h *BaseHandler) SetLevelRange(min_level, max_level LogLevel) {
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	h.LRange = &LevelRange{min_level, max_level}
}

func (h *BaseHandler) SetLevelRangeString(smin, smax string) {
	h.SetLevelRange(StringToLogLevel(smin), StringToLogLevel(smax))
}

func (h *BaseHandler) SetTimeLayout(layout string) {
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	h.TimeLayout = layout
}

func (h *BaseHandler) SetFormat(format string) error {
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	tmpl, err := template.New("tmpl").Parse(format)
	if err != nil {
		return err
	}
	h.Tmpl = tmpl
	return nil
}

func (h *BaseHandler) SetFilter(f func(*Record) bool) {
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	h.Filter = f
}

func (h *BaseHandler) Emit(rd Record) {
	if h.LRange != nil {
		if !h.LRange.Contain(rd.Level) {
			return
		}
	} else if h.Level > rd.Level {
		return
	}
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	h.Buffer <- &rd
}

func (h *BaseHandler) upgrade_buffer() {
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	close(h.Buffer)
	buffer := make(chan *Record, h.BufSize)
	for {
		remain, ok := <-h.Buffer
		if remain == nil || !ok {
			break
		}
		buffer <- remain
	}
	h.Buffer = buffer
}

func (h *BaseHandler) set_state(state bool, err error) {
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	h.State = state
	h.LastError = err
}

func (h *BaseHandler) get_state() (bool, error) {
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	return h.State, h.LastError
}

func (h *BaseHandler) handle_record(rd *Record, buf *bytes.Buffer) {
	defer func() {
		if err := recover(); err != nil {
			h.set_state(false, err.(error))
		}
	}()
	if state, _ := h.get_state(); !state {
		return
	}
	if h.Filter != nil && h.Filter(rd) {
		return
	}
	rd.TimeString = rd.Time.Format(h.TimeLayout)
	buf.Reset()
	if err := h.Tmpl.Execute(buf, rd); err != nil {
		h.set_state(false, err)
		return
	}
	if h.Before != nil {
		h.Before(rd, buf)
	}
	n, err := io.Copy(h.Writer, buf)
	if err != nil {
		h.set_state(false, err)
	}
	if h.After != nil {
		h.After(rd, int64(n))
	}
}

func (h *BaseHandler) WriteRecord() {
	rd := &Record{}
	buf := bytes.NewBuffer(nil)
	for {
		rd = <-h.Buffer
		if rd == nil {
			h.upgrade_buffer()
			go h.WriteRecord()
			break
		}
		h.handle_record(rd, buf)
	}
}

func (h *BaseHandler) notify() {
	c := make(chan os.Signal)
	signal.Notify(c, syscall.SIGHUP)
	for {
		<-c
		h.set_state(true, nil)
	}

}
<commit_msg>add three more log format<commit_after>package logging

import (
	"bytes"
	"io"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"text/template"
	"time"
)

const (
	DefaultTimeLayout = "2006-01-02 15:04:05"
	DefaultFormat     = "[{{.TimeString}}] {{.Level}} {{.Message}}\n"
	FormatNoTime      = "{{.Level}} {{.Message}}\n"
	FormatNoLevel     = "[{{.TimeString}}] {{.Message}}\n"
	FormatOnlyMessage = "{{.Message}}\n"
	DefaultBufSize    = 1024
)

type Handler interface {
	SetBufSize(int)
	SetLevel(LogLevel)
	SetLevelString(string)
	SetLevelRange(LogLevel, LogLevel)
	SetLevelRangeString(string, string)
	SetTimeLayout(string)
	SetFormat(string) error
	SetFilter(func(*Record) bool)
	Emit(Record)
}

type Record struct {
	Time       time.Time
	TimeString string
	Level      LogLevel
	Message    string
}

type BaseHandler struct {
	Mutex      sync.Mutex
	State      bool
	LastError  error
	Writer     io.Writer
	Level      LogLevel
	LRange     *LevelRange
	TimeLayout string
	Tmpl       *template.Template
	Buffer     chan *Record
	BufSize    int
	Filter     func(*Record) bool
	Before     func(*Record, io.ReadWriter)
	After      func(*Record, int64)
}

func NewBaseHandler(out io.Writer, level LogLevel, layout, format string) (*BaseHandler, error) {
	h := &BaseHandler{
		State:      true,
		Writer:     out,
		Level:      level,
		TimeLayout: layout,
	}
	if err := h.SetFormat(format); err != nil {
		return nil, err
	}
	h.BufSize = DefaultBufSize
	h.Buffer = make(chan *Record, h.BufSize)
	go h.notify()
	go h.WriteRecord()
	return h, nil
}

func (h *BaseHandler) SetBufSize(size int) {
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	h.BufSize = size
	h.Buffer <- nil
}

func (h *BaseHandler) SetLevel(level LogLevel) {
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	h.Level = level
}

func (h *BaseHandler) SetLevelString(s string) {
	h.SetLevel(StringToLogLevel(s))
}

func (h *BaseHandler) SetLevelRange(min_level, max_level LogLevel) {
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	h.LRange = &LevelRange{min_level, max_level}
}

func (h *BaseHandler) SetLevelRangeString(smin, smax string) {
	h.SetLevelRange(StringToLogLevel(smin), StringToLogLevel(smax))
}

func (h *BaseHandler) SetTimeLayout(layout string) {
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	h.TimeLayout = layout
}

func (h *BaseHandler) SetFormat(format string) error {
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	tmpl, err := template.New("tmpl").Parse(format)
	if err != nil {
		return err
	}
	h.Tmpl = tmpl
	return nil
}

func (h *BaseHandler) SetFilter(f func(*Record) bool) {
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	h.Filter = f
}

func (h *BaseHandler) Emit(rd Record) {
	if h.LRange != nil {
		if !h.LRange.Contain(rd.Level) {
			return
		}
	} else if h.Level > rd.Level {
		return
	}
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	h.Buffer <- &rd
}

func (h *BaseHandler) upgrade_buffer() {
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	close(h.Buffer)
	buffer := make(chan *Record, h.BufSize)
	for {
		remain, ok := <-h.Buffer
		if remain == nil || !ok {
			break
		}
		buffer <- remain
	}
	h.Buffer = buffer
}

func (h *BaseHandler) set_state(state bool, err error) {
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	h.State = state
	h.LastError = err
}

func (h *BaseHandler) get_state() (bool, error) {
	h.Mutex.Lock()
	defer h.Mutex.Unlock()
	return h.State, h.LastError
}

func (h *BaseHandler) handle_record(rd *Record, buf *bytes.Buffer) {
	defer func() {
		if err := recover(); err != nil {
			h.set_state(false, err.(error))
		}
	}()
	if state, _ := h.get_state(); !state {
		return
	}
	if h.Filter != nil && h.Filter(rd) {
		return
	}
	rd.TimeString = rd.Time.Format(h.TimeLayout)
	buf.Reset()
	if err := h.Tmpl.Execute(buf, rd); err != nil {
		h.set_state(false, err)
		return
	}
	if h.Before != nil {
		h.Before(rd, buf)
	}
	n, err := io.Copy(h.Writer, buf)
	if err != nil {
		h.set_state(false, err)
	}
	if h.After != nil {
		h.After(rd, int64(n))
	}
}

func (h *BaseHandler) WriteRecord() {
	rd := &Record{}
	buf := bytes.NewBuffer(nil)
	for {
		rd = <-h.Buffer
		if rd == nil {
			h.upgrade_buffer()
			go h.WriteRecord()
			break
		}
		h.handle_record(rd, buf)
	}
}

func (h *BaseHandler) notify() {
	c := make(chan os.Signal)
	signal.Notify(c, syscall.SIGHUP)
	for {
		<-c
		h.set_state(true, nil)
	}

}
<|endoftext|>