<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)
	}
	var outPkg string
	fmt.Println(codegen.DesignPackagePath)
	outPkg = strings.ToLower(codegen.DesignPackagePath)
	if err != nil {
		panic(err)
	}
	outPkg = strings.TrimPrefix(outPkg, "src/")
	appPkg := filepath.Join(outPkg, "app")
	imports := []*codegen.ImportSpec{
		codegen.SimpleImport(appPkg),
		codegen.SimpleImport("github.com/jinzhu/gorm"),
		codegen.SimpleImport("github.com/jinzhu/copier"),
		codegen.SimpleImport("database/sql"),
	}

	rbacimports := []*codegen.ImportSpec{
		codegen.SimpleImport(appPkg),
		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>update<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)
	}
	var outPkg string
	fmt.Println(codegen.DesignPackagePath)
	outPkg = codegen.DesignPackagePath[0:strings.LastIndex(codegen.DesignPackagePath, "/")]
	if err != nil {
		panic(err)
	}
	outPkg = strings.TrimPrefix(outPkg, "src/")
	appPkg := filepath.Join(outPkg, "app")
	imports := []*codegen.ImportSpec{
		codegen.SimpleImport(appPkg),
		codegen.SimpleImport("github.com/jinzhu/gorm"),
		codegen.SimpleImport("github.com/jinzhu/copier"),
		codegen.SimpleImport("database/sql"),
	}

	rbacimports := []*codegen.ImportSpec{
		codegen.SimpleImport(appPkg),
		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
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/token"
	"go/types"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"

	"golang.org/x/tools/go/gcimporter15"

	"sourcegraph.com/sourcegraph/srclib-go/gog"
	"sourcegraph.com/sourcegraph/srclib-go/gog/definfo"
	defpkg "sourcegraph.com/sourcegraph/srclib-go/golang_def"
	"sourcegraph.com/sourcegraph/srclib/graph"
	"sourcegraph.com/sourcegraph/srclib/unit"
)

func init() {
	_, err := flagParser.AddCommand("graph",
		"graph a Go package",
		"Graph a Go package, producing all defs, refs, and docs.",
		&graphCmd,
	)
	if err != nil {
		log.Fatal(err)
	}

	// Check that we have the '-i' flag.
	cmd := exec.Command("go", "help", "build")
	o, err := cmd.Output()
	if err != nil {
		log.Fatal(err)
	}
	usage := strings.Split(string(o), "\n")[0] // The usage is on the first line.
	matched, err := regexp.MatchString("-i", usage)
	if err != nil {
		log.Fatal(err)
	}
	if !matched {
		log.Fatal("'go build' does not have the '-i' flag. Please upgrade to go1.3+.")
	}
}

type GraphCmd struct{}

var graphCmd GraphCmd

// allowErrorsInGoGet is whether the grapher should continue after
// if `go get` fails.
var allowErrorsInGoGet = true

func (c *GraphCmd) Execute(args []string) error {
	inputBytes, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		return err
	}
	var unit *unit.SourceUnit
	if err := json.NewDecoder(bytes.NewReader(inputBytes)).Decode(&unit); err != nil {
		return err
	}
	if err := os.Stdin.Close(); err != nil {
		return err
	}

	if err := initBuildContext(); err != nil {
		return err
	}

	out, err := Graph(unit)
	if err != nil {
		return err
	}

	// Make paths relative to repo.
	for _, gs := range out.Defs {
		if gs.File == "" {
			log.Printf("no file %+v", gs)
		}
		if gs.File != "" {
			gs.File = relPath(cwd, gs.File)
		}
	}
	for _, gr := range out.Refs {
		if gr.File != "" {
			gr.File = relPath(cwd, gr.File)
		}
	}
	for _, gd := range out.Docs {
		if gd.File != "" {
			gd.File = relPath(cwd, gd.File)
		}
	}

	if err := json.NewEncoder(os.Stdout).Encode(out); err != nil {
		return err
	}
	return nil
}

func relPath(base, path string) string {
	rp, err := filepath.Rel(evalSymlinks(base), evalSymlinks(path))
	if err != nil {
		log.Fatalf("Failed to make path %q relative to %q: %s", path, base, err)
	}
	return filepath.ToSlash(rp)
}

func Graph(unit *unit.SourceUnit) (*graph.Output, error) {
	pkg, err := UnitDataAsBuildPackage(unit)
	if err != nil {
		return nil, err
	}

	o, err := doGraph(pkg)
	if err != nil {
		return nil, err
	}

	o2 := graph.Output{}

	for _, gs := range o.Defs {
		d, err := convertGoDef(gs)
		if err != nil {
			log.Printf("Ignoring def %v due to error in converting to GoDef: %s.", gs, err)
			continue
		}
		if d != nil {
			o2.Defs = append(o2.Defs, d)
		}
	}
	for _, gr := range o.Refs {
		r, err := convertGoRef(gr)
		if err != nil {
			log.Printf("Ignoring ref %v due to error in converting to GoRef: %s.", gr, err)
			continue
		}
		if r != nil {
			o2.Refs = append(o2.Refs, r)
		}
	}
	for _, gd := range o.Docs {
		d, err := convertGoDoc(gd)
		if err != nil {
			log.Printf("Ignoring doc %v due to error in converting to GoDoc: %s.", gd, err)
			continue
		}
		if d != nil {
			o2.Docs = append(o2.Docs, d)
		}
	}

	return &o2, nil
}

func convertGoDef(gs *gog.Def) (*graph.Def, error) {
	resolvedTarget, err := ResolveDep(gs.DefKey.PackageImportPath)
	if err != nil {
		return nil, err
	}
	path := filepath.ToSlash(pathOrDot(filepath.Join(gs.Path...)))
	treePath := treePath(strings.Replace(string(path), ".go", "", -1))
	if !graph.IsValidTreePath(treePath) {
		return nil, fmt.Errorf("'%s' is not a valid tree-path", treePath)
	}

	def := &graph.Def{
		DefKey: graph.DefKey{
			Unit:     resolvedTarget.ToUnit,
			UnitType: resolvedTarget.ToUnitType,
			Path:     path,
		},
		TreePath: treePath,

		Name: gs.Name,
		Kind: definfo.GeneralKindMap[gs.Kind],

		File:     filepath.ToSlash(gs.File),
		DefStart: gs.DeclSpan[0],
		DefEnd:   gs.DeclSpan[1],

		Exported: gs.DefInfo.Exported,
		Local:    !gs.DefInfo.Exported && !gs.DefInfo.PkgScope,
		Test:     strings.HasSuffix(gs.File, "_test.go"),
	}

	d := defpkg.DefData{
		PackageImportPath: gs.DefKey.PackageImportPath,
		DefInfo:           gs.DefInfo,
	}
	def.Data, err = json.Marshal(d)
	if err != nil {
		return nil, err
	}

	if def.File == "" {
		// some cgo defs have empty File; omit them
		return nil, nil
	}

	return def, nil
}

func convertGoRef(gr *gog.Ref) (*graph.Ref, error) {
	resolvedTarget, err := ResolveDep(gr.Def.PackageImportPath)
	if err != nil {
		return nil, err
	}
	if resolvedTarget == nil {
		return nil, nil
	}

	resolvedRefUnit, err := ResolveDep(gr.Unit)
	if err != nil {
		return nil, err
	}
	if resolvedRefUnit == nil {
		return nil, nil
	}

	return &graph.Ref{
		DefRepo:     filepath.ToSlash(uriOrEmpty(resolvedTarget.ToRepoCloneURL)),
		DefPath:     filepath.ToSlash(pathOrDot(filepath.Join(gr.Def.Path...))),
		DefUnit:     resolvedTarget.ToUnit,
		DefUnitType: resolvedTarget.ToUnitType,
		Def:         gr.IsDef,
		Unit:        resolvedRefUnit.ToUnit,
		File:        filepath.ToSlash(gr.File),
		Start:       gr.Span[0],
		End:         gr.Span[1],
	}, nil
}

func convertGoDoc(gd *gog.Doc) (*graph.Doc, error) {
	var key graph.DefKey
	if gd.DefKey != nil {
		resolvedTarget, err := ResolveDep(gd.PackageImportPath)
		if err != nil {
			return nil, err
		}
		key = graph.DefKey{
			Path:     filepath.ToSlash(pathOrDot(filepath.Join(gd.Path...))),
			Unit:     resolvedTarget.ToUnit,
			UnitType: resolvedTarget.ToUnitType,
		}
	}

	resolvedDocUnit, err := ResolveDep(gd.Unit)
	if err != nil {
		return nil, err
	}
	if resolvedDocUnit == nil {
		return nil, nil
	}

	return &graph.Doc{
		DefKey:  key,
		Format:  gd.Format,
		Data:    gd.Data,
		File:    filepath.ToSlash(gd.File),
		Start:   gd.Span[0],
		End:     gd.Span[1],
		DocUnit: resolvedDocUnit.ToUnit,
	}, nil
}

func uriOrEmpty(cloneURL string) string {
	if cloneURL == "" {
		return ""
	}
	return graph.MakeURI(cloneURL)
}

func pathOrDot(path string) string {
	if path == "" {
		return "."
	}
	return path
}

func treePath(path string) string {
	if path == "" || path == "." {
		return string(".")
	}
	return "./" + path
}

func doGraph(pkg *build.Package) (*gog.Output, error) {
	var allGoFiles []string
	allGoFiles = append(allGoFiles, pkg.GoFiles...)
	allGoFiles = append(allGoFiles, pkg.CgoFiles...)
	allGoFiles = append(allGoFiles, pkg.TestGoFiles...)
	if len(allGoFiles) == 0 {
		return &gog.Output{}, nil
	}

	fset := token.NewFileSet()
	var files []*ast.File
	for _, name := range allGoFiles {
		file, err := parser.ParseFile(fset, filepath.Join(pkg.Dir, name), nil, parser.ParseComments)
		if err != nil {
			return nil, err
		}
		files = append(files, file)
	}

	typesConfig := &types.Config{
		Importer: &buildContextImporter{
			context: &buildContext,
			srcDir:  pkg.Dir,
			fset:    fset,
			packages: map[string]*types.Package{
				"unsafe": types.Unsafe,
			},
		},
		FakeImportC: true,
		Error: func(err error) {
			// errors are ignored, use best-effort type checking output
		},
	}
	typesInfo := &types.Info{
		Defs:       make(map[*ast.Ident]types.Object),
		Uses:       make(map[*ast.Ident]types.Object),
		Implicits:  make(map[ast.Node]types.Object),
		Selections: make(map[*ast.SelectorExpr]*types.Selection),
		Scopes:     make(map[ast.Node]*types.Scope),
	}
	typesPkg, err := typesConfig.Check(pkg.ImportPath, fset, files, typesInfo)
	if err != nil {
		log.Println("type checker error:", err) // see comment above
	}

	return gog.Graph(fset, files, typesPkg, typesInfo, true), nil
}

type buildContextImporter struct {
	context  *build.Context
	srcDir   string
	fset     *token.FileSet
	packages map[string]*types.Package
}

func (i *buildContextImporter) Import(path string) (*types.Package, error) {
	buildPkg, err := i.context.Import(path, i.srcDir, build.FindOnly&build.AllowBinary)
	if err != nil {
		return nil, err
	}

	if typesPkg, ok := i.packages[buildPkg.ImportPath]; ok && typesPkg.Complete() {
		return typesPkg, nil
	}

	if _, err := os.Stat(buildPkg.PkgObj); os.IsNotExist(err) {
		// try to build .a file if it does not exist
		cmd := exec.Command("go", "install", "-buildmode=archive", buildPkg.ImportPath)
		cmd.Env = []string{"PATH=" + os.Getenv("PATH"), "GOROOT=" + i.context.GOROOT, "GOPATH=" + i.context.GOPATH, "CGO_ENABLED=0"}
		cmd.Stderr = os.Stderr
		if err := cmd.Run(); err != nil {
			return nil, err
		}
	}

	r, err := os.Open(buildPkg.PkgObj)
	if err != nil {
		return nil, err
	}
	defer r.Close()

	br := bufio.NewReader(r)

	hdr, err := gcimporter.FindExportData(br)
	if err != nil {
		return nil, err
	}

	switch hdr {
	case "$$\n":
		return gcimporter.ImportData(i.packages, buildPkg.PkgObj, buildPkg.ImportPath, br)
	case "$$B\n":
		var data []byte
		data, err = ioutil.ReadAll(br)
		if err != nil {
			return nil, err
		}
		_, pkg, err := gcimporter.BImportData(i.fset, i.packages, data, buildPkg.ImportPath)
		return pkg, err
	default:
		return nil, fmt.Errorf("unknown export data header: %q", hdr)
	}
}
<commit_msg>Revert "disable CGO when building .a files"<commit_after>package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/token"
	"go/types"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"

	"golang.org/x/tools/go/gcimporter15"

	"sourcegraph.com/sourcegraph/srclib-go/gog"
	"sourcegraph.com/sourcegraph/srclib-go/gog/definfo"
	defpkg "sourcegraph.com/sourcegraph/srclib-go/golang_def"
	"sourcegraph.com/sourcegraph/srclib/graph"
	"sourcegraph.com/sourcegraph/srclib/unit"
)

func init() {
	_, err := flagParser.AddCommand("graph",
		"graph a Go package",
		"Graph a Go package, producing all defs, refs, and docs.",
		&graphCmd,
	)
	if err != nil {
		log.Fatal(err)
	}

	// Check that we have the '-i' flag.
	cmd := exec.Command("go", "help", "build")
	o, err := cmd.Output()
	if err != nil {
		log.Fatal(err)
	}
	usage := strings.Split(string(o), "\n")[0] // The usage is on the first line.
	matched, err := regexp.MatchString("-i", usage)
	if err != nil {
		log.Fatal(err)
	}
	if !matched {
		log.Fatal("'go build' does not have the '-i' flag. Please upgrade to go1.3+.")
	}
}

type GraphCmd struct{}

var graphCmd GraphCmd

// allowErrorsInGoGet is whether the grapher should continue after
// if `go get` fails.
var allowErrorsInGoGet = true

func (c *GraphCmd) Execute(args []string) error {
	inputBytes, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		return err
	}
	var unit *unit.SourceUnit
	if err := json.NewDecoder(bytes.NewReader(inputBytes)).Decode(&unit); err != nil {
		return err
	}
	if err := os.Stdin.Close(); err != nil {
		return err
	}

	if err := initBuildContext(); err != nil {
		return err
	}

	out, err := Graph(unit)
	if err != nil {
		return err
	}

	// Make paths relative to repo.
	for _, gs := range out.Defs {
		if gs.File == "" {
			log.Printf("no file %+v", gs)
		}
		if gs.File != "" {
			gs.File = relPath(cwd, gs.File)
		}
	}
	for _, gr := range out.Refs {
		if gr.File != "" {
			gr.File = relPath(cwd, gr.File)
		}
	}
	for _, gd := range out.Docs {
		if gd.File != "" {
			gd.File = relPath(cwd, gd.File)
		}
	}

	if err := json.NewEncoder(os.Stdout).Encode(out); err != nil {
		return err
	}
	return nil
}

func relPath(base, path string) string {
	rp, err := filepath.Rel(evalSymlinks(base), evalSymlinks(path))
	if err != nil {
		log.Fatalf("Failed to make path %q relative to %q: %s", path, base, err)
	}
	return filepath.ToSlash(rp)
}

func Graph(unit *unit.SourceUnit) (*graph.Output, error) {
	pkg, err := UnitDataAsBuildPackage(unit)
	if err != nil {
		return nil, err
	}

	o, err := doGraph(pkg)
	if err != nil {
		return nil, err
	}

	o2 := graph.Output{}

	for _, gs := range o.Defs {
		d, err := convertGoDef(gs)
		if err != nil {
			log.Printf("Ignoring def %v due to error in converting to GoDef: %s.", gs, err)
			continue
		}
		if d != nil {
			o2.Defs = append(o2.Defs, d)
		}
	}
	for _, gr := range o.Refs {
		r, err := convertGoRef(gr)
		if err != nil {
			log.Printf("Ignoring ref %v due to error in converting to GoRef: %s.", gr, err)
			continue
		}
		if r != nil {
			o2.Refs = append(o2.Refs, r)
		}
	}
	for _, gd := range o.Docs {
		d, err := convertGoDoc(gd)
		if err != nil {
			log.Printf("Ignoring doc %v due to error in converting to GoDoc: %s.", gd, err)
			continue
		}
		if d != nil {
			o2.Docs = append(o2.Docs, d)
		}
	}

	return &o2, nil
}

func convertGoDef(gs *gog.Def) (*graph.Def, error) {
	resolvedTarget, err := ResolveDep(gs.DefKey.PackageImportPath)
	if err != nil {
		return nil, err
	}
	path := filepath.ToSlash(pathOrDot(filepath.Join(gs.Path...)))
	treePath := treePath(strings.Replace(string(path), ".go", "", -1))
	if !graph.IsValidTreePath(treePath) {
		return nil, fmt.Errorf("'%s' is not a valid tree-path", treePath)
	}

	def := &graph.Def{
		DefKey: graph.DefKey{
			Unit:     resolvedTarget.ToUnit,
			UnitType: resolvedTarget.ToUnitType,
			Path:     path,
		},
		TreePath: treePath,

		Name: gs.Name,
		Kind: definfo.GeneralKindMap[gs.Kind],

		File:     filepath.ToSlash(gs.File),
		DefStart: gs.DeclSpan[0],
		DefEnd:   gs.DeclSpan[1],

		Exported: gs.DefInfo.Exported,
		Local:    !gs.DefInfo.Exported && !gs.DefInfo.PkgScope,
		Test:     strings.HasSuffix(gs.File, "_test.go"),
	}

	d := defpkg.DefData{
		PackageImportPath: gs.DefKey.PackageImportPath,
		DefInfo:           gs.DefInfo,
	}
	def.Data, err = json.Marshal(d)
	if err != nil {
		return nil, err
	}

	if def.File == "" {
		// some cgo defs have empty File; omit them
		return nil, nil
	}

	return def, nil
}

func convertGoRef(gr *gog.Ref) (*graph.Ref, error) {
	resolvedTarget, err := ResolveDep(gr.Def.PackageImportPath)
	if err != nil {
		return nil, err
	}
	if resolvedTarget == nil {
		return nil, nil
	}

	resolvedRefUnit, err := ResolveDep(gr.Unit)
	if err != nil {
		return nil, err
	}
	if resolvedRefUnit == nil {
		return nil, nil
	}

	return &graph.Ref{
		DefRepo:     filepath.ToSlash(uriOrEmpty(resolvedTarget.ToRepoCloneURL)),
		DefPath:     filepath.ToSlash(pathOrDot(filepath.Join(gr.Def.Path...))),
		DefUnit:     resolvedTarget.ToUnit,
		DefUnitType: resolvedTarget.ToUnitType,
		Def:         gr.IsDef,
		Unit:        resolvedRefUnit.ToUnit,
		File:        filepath.ToSlash(gr.File),
		Start:       gr.Span[0],
		End:         gr.Span[1],
	}, nil
}

func convertGoDoc(gd *gog.Doc) (*graph.Doc, error) {
	var key graph.DefKey
	if gd.DefKey != nil {
		resolvedTarget, err := ResolveDep(gd.PackageImportPath)
		if err != nil {
			return nil, err
		}
		key = graph.DefKey{
			Path:     filepath.ToSlash(pathOrDot(filepath.Join(gd.Path...))),
			Unit:     resolvedTarget.ToUnit,
			UnitType: resolvedTarget.ToUnitType,
		}
	}

	resolvedDocUnit, err := ResolveDep(gd.Unit)
	if err != nil {
		return nil, err
	}
	if resolvedDocUnit == nil {
		return nil, nil
	}

	return &graph.Doc{
		DefKey:  key,
		Format:  gd.Format,
		Data:    gd.Data,
		File:    filepath.ToSlash(gd.File),
		Start:   gd.Span[0],
		End:     gd.Span[1],
		DocUnit: resolvedDocUnit.ToUnit,
	}, nil
}

func uriOrEmpty(cloneURL string) string {
	if cloneURL == "" {
		return ""
	}
	return graph.MakeURI(cloneURL)
}

func pathOrDot(path string) string {
	if path == "" {
		return "."
	}
	return path
}

func treePath(path string) string {
	if path == "" || path == "." {
		return string(".")
	}
	return "./" + path
}

func doGraph(pkg *build.Package) (*gog.Output, error) {
	var allGoFiles []string
	allGoFiles = append(allGoFiles, pkg.GoFiles...)
	allGoFiles = append(allGoFiles, pkg.CgoFiles...)
	allGoFiles = append(allGoFiles, pkg.TestGoFiles...)
	if len(allGoFiles) == 0 {
		return &gog.Output{}, nil
	}

	fset := token.NewFileSet()
	var files []*ast.File
	for _, name := range allGoFiles {
		file, err := parser.ParseFile(fset, filepath.Join(pkg.Dir, name), nil, parser.ParseComments)
		if err != nil {
			return nil, err
		}
		files = append(files, file)
	}

	typesConfig := &types.Config{
		Importer: &buildContextImporter{
			context: &buildContext,
			srcDir:  pkg.Dir,
			fset:    fset,
			packages: map[string]*types.Package{
				"unsafe": types.Unsafe,
			},
		},
		FakeImportC: true,
		Error: func(err error) {
			// errors are ignored, use best-effort type checking output
		},
	}
	typesInfo := &types.Info{
		Defs:       make(map[*ast.Ident]types.Object),
		Uses:       make(map[*ast.Ident]types.Object),
		Implicits:  make(map[ast.Node]types.Object),
		Selections: make(map[*ast.SelectorExpr]*types.Selection),
		Scopes:     make(map[ast.Node]*types.Scope),
	}
	typesPkg, err := typesConfig.Check(pkg.ImportPath, fset, files, typesInfo)
	if err != nil {
		log.Println("type checker error:", err) // see comment above
	}

	return gog.Graph(fset, files, typesPkg, typesInfo, true), nil
}

type buildContextImporter struct {
	context  *build.Context
	srcDir   string
	fset     *token.FileSet
	packages map[string]*types.Package
}

func (i *buildContextImporter) Import(path string) (*types.Package, error) {
	buildPkg, err := i.context.Import(path, i.srcDir, build.FindOnly&build.AllowBinary)
	if err != nil {
		return nil, err
	}

	if typesPkg, ok := i.packages[buildPkg.ImportPath]; ok && typesPkg.Complete() {
		return typesPkg, nil
	}

	if _, err := os.Stat(buildPkg.PkgObj); os.IsNotExist(err) {
		// try to build .a file if it does not exist
		cmd := exec.Command("go", "install", "-buildmode=archive", buildPkg.ImportPath)
		cmd.Env = []string{"PATH=" + os.Getenv("PATH"), "GOROOT=" + i.context.GOROOT, "GOPATH=" + i.context.GOPATH}
		cmd.Stderr = os.Stderr
		if err := cmd.Run(); err != nil {
			return nil, err
		}
	}

	r, err := os.Open(buildPkg.PkgObj)
	if err != nil {
		return nil, err
	}
	defer r.Close()

	br := bufio.NewReader(r)

	hdr, err := gcimporter.FindExportData(br)
	if err != nil {
		return nil, err
	}

	switch hdr {
	case "$$\n":
		return gcimporter.ImportData(i.packages, buildPkg.PkgObj, buildPkg.ImportPath, br)
	case "$$B\n":
		var data []byte
		data, err = ioutil.ReadAll(br)
		if err != nil {
			return nil, err
		}
		_, pkg, err := gcimporter.BImportData(i.fset, i.packages, data, buildPkg.ImportPath)
		return pkg, err
	default:
		return nil, fmt.Errorf("unknown export data header: %q", hdr)
	}
}
<|endoftext|>


<commit_before>package google

import (
	"context"
	"fmt"
	"net/http"

	"github.com/docker/distribution/reference"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"

	voucher "github.com/grafeas/voucher/v2"
	"github.com/grafeas/voucher/v2/auth"
)

const gcrScope = "https://www.googleapis.com/auth/cloud-platform"

// GoogleAuth wraps the Google OAuth2 code.
type gAuth struct {
}

// GetTokenSource gets the default oauth2.TokenSource for connecting to Google's,
// OAuth2 protected systems, based on the runtime environment, or returns error
// if there's an issue getting the token source.
func (a *gAuth) GetTokenSource(ctx context.Context, ref reference.Named) (oauth2.TokenSource, error) {
	source, err := google.DefaultTokenSource(ctx, gcrScope)
	if nil != err {
		err = fmt.Errorf("failed to get Google Auth token source: %s", err)
	}

	return source, err
}

// ToClient returns a new http.Client with the authentication details setup by
// Auth.GetTokenSource.
func (a *gAuth) ToClient(ctx context.Context, image reference.Named) (*http.Client, error) {
	if !a.IsForDomain(image) {
		return nil, auth.NewAuthError("does not match domain", image)
	}

	tokenSource, err := a.GetTokenSource(ctx, image)
	if nil != err {
		return nil, err
	}

	client := oauth2.NewClient(ctx, tokenSource)
	err = auth.UpdateIdleConnectionsTimeout(client)

	return client, err
}

// IsForDomain validates the domain part of the Named image reference
func (a *gAuth) IsForDomain(image reference.Named) bool {
	return "gcr.io" == reference.Domain(image)
}

// NewAuth returns a new voucher.Auth to access Google specific resources.
func NewAuth() voucher.Auth {
	return new(gAuth)
}
<commit_msg>auth hardcodes GCR too<commit_after>package google

import (
	"context"
	"fmt"
	"net/http"
	"strings"

	"github.com/docker/distribution/reference"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"

	voucher "github.com/grafeas/voucher/v2"
	"github.com/grafeas/voucher/v2/auth"
)

const gcrScope = "https://www.googleapis.com/auth/cloud-platform"

// GoogleAuth wraps the Google OAuth2 code.
type gAuth struct {
}

// GetTokenSource gets the default oauth2.TokenSource for connecting to Google's,
// OAuth2 protected systems, based on the runtime environment, or returns error
// if there's an issue getting the token source.
func (a *gAuth) GetTokenSource(ctx context.Context, ref reference.Named) (oauth2.TokenSource, error) {
	source, err := google.DefaultTokenSource(ctx, gcrScope)
	if nil != err {
		err = fmt.Errorf("failed to get Google Auth token source: %s", err)
	}

	return source, err
}

// ToClient returns a new http.Client with the authentication details setup by
// Auth.GetTokenSource.
func (a *gAuth) ToClient(ctx context.Context, image reference.Named) (*http.Client, error) {
	if !a.IsForDomain(image) {
		return nil, auth.NewAuthError("does not match domain", image)
	}

	tokenSource, err := a.GetTokenSource(ctx, image)
	if nil != err {
		return nil, err
	}

	client := oauth2.NewClient(ctx, tokenSource)
	err = auth.UpdateIdleConnectionsTimeout(client)

	return client, err
}

// IsForDomain validates the domain part of the Named image reference
func (a *gAuth) IsForDomain(image reference.Named) bool {
	domain := reference.Domain(image)
	if domain == "gcr.io" {
		// Google Container Registry
		return true
	}

	// Google Artifact Registry
	return strings.HasSuffix(domain, ".pkg.dev")
}

// NewAuth returns a new voucher.Auth to access Google specific resources.
func NewAuth() voucher.Auth {
	return new(gAuth)
}
<|endoftext|>


<commit_before>//There is one rule here. "thou shall not block"
//Slack Technologies, Inc 2015
//Ryan Huber
package main

import (
	_ "bufio"
	"fmt"
	"github.com/spf13/viper"
	"log"
	"os"
	"os/exec"
	"runtime/pprof"
	"strings"
	"syscall"
)

var count int

func ping(count *int, interval int) bool {
	*count++
	return (*count % interval) == 0
}

func connect() (conn *NetlinkConnection) {
	conn, err := newNetlinkConnection()
	if err != nil {
		log.Fatal(err)
	}
	return

}

func startFlow(conn *NetlinkConnection) {
	//this mask starts the flow
	var ret []byte
	a, err := newAuditStatusPayload()
	a.Mask = 4
	a.Enabled = 1
	a.Pid = uint32(syscall.Getpid())

	n := newNetlinkPacket(1001)

	ret, _ = AuditRequestSerialize(n, a)
	//PrettyPacketSplit(ret, []int{32, 48, 64, 96, 128, 160, 192, 224, 256, 288})

	err = conn.Send(&ret)
	if err != nil {
		fmt.Println("something broke")
	}
}

//Helper for profiling. Don't forget to "pprof.StopCPUProfile()" at some point or the file isn't written.
func profile() {
	f, err := os.Create("/tmp/profile")
	if err != nil {
		log.Fatal(err)
	}
	f2, err := os.Create("/tmp/profile2")
	if err != nil {
		log.Fatal(err)
	}
	pprof.StartCPUProfile(f)
	pprof.WriteHeapProfile(f2)
}

func loadConfig() {
	viper.SetConfigName("go-audit")
	viper.AddConfigPath("/etc/audit")
	viper.AddConfigPath(".")
	err := viper.ReadInConfig() // Find and read the config file
	if err != nil {             // Handle errors reading the config file
		fmt.Println("Config not found. Running in default mode. (forwarding all events to syslog)")
		return
	}
	if viper.GetBool("canary") {
		go canaryGo(viper.GetString("canary_host"), viper.GetString("canary_port"))
	}
	if rules := viper.GetStringSlice("rules"); len(rules) != 0 {
		for _, v := range rules {
			var _ = v
			v := strings.Fields(v)
			err := exec.Command("auditctl", v...).Run()
			if err != nil {
				fmt.Println("auditctl exit info: ", err)
			}
		}
	} else {
		fmt.Println("No rules found. Running with existing ruleset (may be empty!)")
	}
}

func main() {

	loadConfig()

	//This buffer holds partial events because they come as associated but separate lines from the kernel
	eventBuffer := make(map[int]map[string]string)

	conn := connect()
	startFlow(conn)

	//Main loop. Get data from netlink and send it to the json lib for processing
	for {
		data, _ := conn.Receive()
		header := readNetlinkPacketHeader(data[:16])
		dstring := fmt.Sprintf("%s", data[16:])
		logLine(makeJsonString(eventBuffer, header.Type, dstring))
	}
}
<commit_msg>much much faster<commit_after>//There is one rule here. "thou shall not block"
//Slack Technologies, Inc 2015
//Ryan Huber
package main

import (
	_ "bufio"
	"fmt"
	"github.com/spf13/viper"
	"log"
	"os"
	"os/exec"
	"runtime/pprof"
	"strings"
	"syscall"
)

var count int

func ping(count *int, interval int) bool {
	*count++
	return (*count % interval) == 0
}

func connect() (conn *NetlinkConnection) {
	conn, err := newNetlinkConnection()
	if err != nil {
		log.Fatal(err)
	}
	return

}

func startFlow(conn *NetlinkConnection) {
	//this mask starts the flow
	var ret []byte
	a, err := newAuditStatusPayload()
	a.Mask = 4
	a.Enabled = 1
	a.Pid = uint32(syscall.Getpid())

	n := newNetlinkPacket(1001)

	ret, _ = AuditRequestSerialize(n, a)
	//PrettyPacketSplit(ret, []int{32, 48, 64, 96, 128, 160, 192, 224, 256, 288})

	err = conn.Send(&ret)
	if err != nil {
		fmt.Println("something broke")
	}
}

//Helper for profiling. Don't forget to "pprof.StopCPUProfile()" at some point or the file isn't written.
func profile() {
	f, err := os.Create("/tmp/profile")
	if err != nil {
		log.Fatal(err)
	}
	f2, err := os.Create("/tmp/profile2")
	if err != nil {
		log.Fatal(err)
	}
	pprof.StartCPUProfile(f)
	pprof.WriteHeapProfile(f2)
}

func loadConfig() {
	viper.SetConfigName("go-audit")
	viper.AddConfigPath("/etc/audit")
	viper.AddConfigPath(".")
	err := viper.ReadInConfig() // Find and read the config file
	if err != nil {             // Handle errors reading the config file
		fmt.Println("Config not found. Running in default mode. (forwarding all events to syslog)")
		return
	}
	if viper.GetBool("canary") {
		go canaryGo(viper.GetString("canary_host"), viper.GetString("canary_port"))
	}
	if rules := viper.GetStringSlice("rules"); len(rules) != 0 {
		for _, v := range rules {
			var _ = v
			v := strings.Fields(v)
			err := exec.Command("auditctl", v...).Run()
			if err != nil {
				fmt.Println("auditctl exit info: ", err)
			}
		}
	} else {
		fmt.Println("No rules found. Running with existing ruleset (may be empty!)")
	}
}

func main() {

	loadConfig()

	//This buffer holds partial events because they come as associated but separate lines from the kernel
	eventBuffer := make(map[int]map[string]string)

	conn := connect()
	startFlow(conn)

	//Main loop. Get data from netlink and send it to the json lib for processing
	for {
		data, _ := conn.Receive()
		header := readNetlinkPacketHeader(data[:16])
		dstring := fmt.Sprintf("%s", data[16:])
		jstring := makeJsonString(eventBuffer, header.Type, dstring)
		if jstring != "" {
			logLine(jstring)
		}

	}
}
<|endoftext|>


<commit_before>// Copyright 2013 - by Jim Lawless
// License: MIT / X11
// See: http://www.mailsend-online.com/license2013.php
//
// Bear with me ... I'm a Go noob.

package main

import (
	"flag"
	"fmt"
	"log"
	"net/smtp"
)

func main() {
	to := flag.String("t", "", "destination Internet mail address")
	from := flag.String("f", "", "the sender's GMail address")
	pwd := flag.String("p", "", "the sender's password")
	subject := flag.String("s", "", "subject line of email")
	msg := flag.String("m", "", "a one-line email message")
	flag.Usage = func() {
		fmt.Printf("Syntax:\n\tGSend [flags]\nwhere flags are:\n")
		flag.PrintDefaults()
	}

	fmt.Printf("GSend v 1.01 by Jim Lawless\n")

	flag.Parse()

	if flag.NFlag() != 5 {
		flag.Usage()
		return
	}

	body := "To: " + *to + "\r\nSubject: " +
		*subject + "\r\n\r\n" + *msg
	auth := smtp.PlainAuth("", *from, *pwd, "smtp.gmail.com")
	err := smtp.SendMail("smtp.gmail.com:587", auth, *from,
		[]string{*to}, []byte(body))
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Usage: Command name is lowercase<commit_after>// Copyright 2013 - by Jim Lawless
// License: MIT / X11
// See: http://www.mailsend-online.com/license2013.php
//
// Bear with me ... I'm a Go noob.

package main

import (
	"flag"
	"fmt"
	"log"
	"net/smtp"
)

func main() {
	to := flag.String("t", "", "destination Internet mail address")
	from := flag.String("f", "", "the sender's GMail address")
	pwd := flag.String("p", "", "the sender's password")
	subject := flag.String("s", "", "subject line of email")
	msg := flag.String("m", "", "a one-line email message")
	flag.Usage = func() {
		fmt.Printf("Syntax:\n\tgsend [flags]\nwhere flags are:\n")
		flag.PrintDefaults()
	}

	fmt.Printf("GSend v 1.01 by Jim Lawless\n")

	flag.Parse()

	if flag.NFlag() != 5 {
		flag.Usage()
		return
	}

	body := "To: " + *to + "\r\nSubject: " +
		*subject + "\r\n\r\n" + *msg
	auth := smtp.PlainAuth("", *from, *pwd, "smtp.gmail.com")
	err := smtp.SendMail("smtp.gmail.com:587", auth, *from,
		[]string{*to}, []byte(body))
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package editor

import "github.com/nsf/termbox-go"
import "fmt"
import "os"
import "io/ioutil"
import "path/filepath"
import "github.com/wx13/sith/syntaxcolor"
import "github.com/wx13/sith/terminal"
import "github.com/wx13/sith/file"

type Editor struct {
	screen     *terminal.Screen
	file       *file.File
	files      []*file.File
	fileIdx    int
	fileIdxPrv int
	keyboard   *terminal.Keyboard
	flushChan  chan struct{}

	searchHist  []string
	replaceHist []string

	copyBuffer file.Buffer
	copyContig int
	copyHist   []file.Buffer
}

func NewEditor() *Editor {
	return &Editor{
		flushChan:  make(chan struct{}, 1),
		screen:     terminal.NewScreen(),
		copyBuffer: file.MakeBuffer([]string{}),
		copyContig: 0,
		copyHist:   []file.Buffer{},
	}
}

func (editor *Editor) OpenNewFile() {
	dir, _ := os.Getwd()
	dir += "/"
	names := []string{}
	idx := 0
	files := []os.FileInfo{}
	for {
		files, _ = ioutil.ReadDir(dir)
		dotdot, err := os.Stat("../")
		if err == nil {
			files = append([]os.FileInfo{dotdot}, files...)
		}
		names = []string{}
		for _, file := range files {
			if file.IsDir() {
				names = append(names, file.Name()+"/")
			} else {
				names = append(names, file.Name())
			}
		}
		menu := terminal.NewMenu(editor.screen)
		idx = menu.Choose(names)
		editor.Flush()
		if idx < 0 {
			return
		}
		chosenFile := files[idx]
		if chosenFile.IsDir() {
			dir = filepath.Clean(dir+chosenFile.Name()) + "/"
		} else {
			break
		}
	}
	cwd, _ := os.Getwd()
	chosenFile, _ := filepath.Rel(cwd, dir+names[idx])
	editor.OpenFile(chosenFile)
	editor.fileIdxPrv = editor.fileIdx
	editor.fileIdx = len(editor.files) - 1
	editor.file = editor.files[editor.fileIdx]
}

func (editor *Editor) OpenFile(name string) {
	file := file.NewFile(name, editor.flushChan, editor.screen)
	file.SyntaxRules = syntaxcolor.NewSyntaxRules(name)
	editor.files = append(editor.files, file)
}

func (editor *Editor) OpenFiles(fileNames []string) {
	for _, name := range fileNames {
		editor.OpenFile(name)
	}
	if len(editor.files) == 0 {
		editor.files = append(editor.files, file.NewFile("", editor.flushChan, editor.screen))
	}
	editor.fileIdx = 0
	editor.fileIdxPrv = 0
	editor.file = editor.files[0]
}

func (editor *Editor) Quit() {
	for _, _ = range editor.files {
		if !editor.CloseFile() {
			editor.NextFile()
		}
	}
}

func (editor *Editor) CloseFile() bool {
	editor.Flush()
	idx := editor.fileIdx
	if !editor.files[idx].Close() {
		return false
	}
	editor.files = append(editor.files[:idx], editor.files[idx+1:]...)
	if len(editor.files) == 0 {
		editor.screen.Close()
		return true
	}
	editor.NextFile()
	return true
}

func (editor *Editor) Listen() {

	keyboard := terminal.NewKeyboard()
	for {
		cmd, r := keyboard.GetKey()
		switch cmd {
		case "backspace":
			editor.file.Backspace()
		case "delete", "ctrlD":
			editor.file.Delete()
		case "space":
			editor.file.InsertChar(' ')
		case "tab":
			editor.file.InsertChar('\t')
		case "enter":
			editor.file.Newline()
		case "arrowLeft", "ctrlO":
			editor.file.CursorLeft()
		case "arrowRight", "ctrlL":
			editor.file.CursorRight()
		case "arrowUp", "ctrlK":
			editor.file.CursorUp(1)
		case "arrowDown", "ctrlJ":
			editor.file.CursorDown(1)
		case "ctrlU":
			editor.file.ScrollUp()
		case "ctrlP":
			editor.file.ScrollDown()
		case "altP":
			editor.file.ScrollRight()
		case "altU":
			editor.file.ScrollLeft()
		case "pageDown", "ctrlN":
			editor.file.PageDown()
		case "pageUp", "ctrlB":
			editor.file.PageUp()
		case "ctrlG":
			editor.file.GoToLine()
		case "altL":
			editor.file.Refresh()
		case "altO":
			editor.OpenNewFile()
		case "altQ":
			editor.Quit()
		case "altW":
			editor.CloseFile()
		case "altZ":
			editor.Suspend()
			keyboard = terminal.NewKeyboard()
		case "altN":
			editor.NextFile()
		case "altB":
			editor.PrevFile()
		case "altK":
			editor.LastFile()
		case "altM":
			editor.SelectFile()
		case "ctrlX":
			editor.file.AddCursor()
		case "altC":
			editor.file.AddCursorCol()
		case "altX":
			editor.file.ClearCursors()
		case "ctrlZ":
			editor.Undo()
		case "ctrlY":
			editor.Redo()
		case "ctrlS":
			editor.Save()
		case "ctrlA":
			editor.file.StartOfLine()
		case "ctrlE":
			editor.file.EndOfLine()
		case "ctrlW":
			editor.file.NextWord()
		case "ctrlQ":
			editor.file.PrevWord()
		case "ctrlF":
			editor.Search(false)
		case "altF":
			editor.SearchAndReplace(false)
		case "ctrlR":
			editor.Search(true)
		case "altR":
			editor.SearchAndReplace(true)
		case "ctrlC":
			editor.Cut()
		case "ctrlV":
			editor.Paste()
		case "altV":
			editor.PasteFromMenu()
		case "altG":
			editor.GoFmt()
		case "altJ":
			editor.file.Justify(72)
		case "altE":
			editor.file.Justify(0)
		case "altI":
			editor.file.ToggleAutoIndent()
		case "altT":
			editor.file.ToggleAutoTab()
		case "unknown":
			editor.screen.Notify("Unknown keypress")
		case "char":
			editor.file.InsertChar(r)
		default:
			editor.screen.Notify("Unknown keypress")
		}
		editor.copyContig--
		editor.RequestFlush()
	}

}

func (editor *Editor) Undo() {
	editor.file.Undo()
}

func (editor *Editor) Redo() {
	editor.file.Redo()
}

func (editor *Editor) NextFile() {
	editor.SwitchFile(editor.fileIdx + 1)
}

func (editor *Editor) PrevFile() {
	editor.SwitchFile(editor.fileIdx - 1)
}

func (editor *Editor) LastFile() {
	editor.SwitchFile(editor.fileIdxPrv)
}

func (editor *Editor) SelectFile() {
	names := []string{}
	for _, file := range editor.files {
		names = append(names, file.Name)
	}
	menu := terminal.NewMenu(editor.screen)
	idx := menu.Choose(names)
	if idx >= 0 {
		editor.SwitchFile(idx)
	}
}

func (editor *Editor) Save() {
	filetype := editor.file.SyntaxRules.GetFileType(editor.file.Name)
	if filetype == "go" {
		editor.GoFmt()
	}
	editor.file.RequestSave()
}

func (editor *Editor) GoFmt() {
	err := editor.file.GoFmt()
	if err == nil {
		editor.RequestFlush()
		editor.file.NotifyUser("GoFmt done")
	} else {
		editor.file.NotifyUser(err.Error())
	}
}

func intMod(a, n int) int {
	if a >= 0 {
		return a - n*(a/n)
	} else {
		return a - n*((a-n+1)/n)
	}
}

func (editor *Editor) SwitchFile(n int) {
	n = intMod(n, len(editor.files))
	editor.fileIdxPrv = editor.fileIdx
	editor.fileIdx = n
	editor.file = editor.files[n]
}

func (editor *Editor) HighlightCursors() {
	cells := termbox.CellBuffer()
	cols, _ := termbox.Size()
	for k, _ := range editor.file.MultiCursor[1:] {
		r, c := editor.file.GetCursor(k + 1)
		j := r*cols + c
		if j < 0 || j >= len(cells) {
			continue
		}
		cells[j].Bg |= termbox.AttrReverse
		cells[j].Fg |= termbox.AttrReverse
	}
}

func (editor *Editor) Flush() {
	editor.file.Flush()
	editor.HighlightCursors()
	editor.UpdateStatus()
	editor.screen.Flush()
}

func (editor *Editor) KeepFlushed() {
	go func() {
		for {
			<-editor.flushChan
			editor.Flush()
		}
	}()
}

func (editor *Editor) RequestFlush() {
	select {
	case editor.flushChan <- struct{}{}:
	default:
	}
}

func (editor *Editor) UpdateStatus() {
	cols, rows := termbox.Size()
	maxNameLen := cols / 3
	name := editor.file.Name
	nameLen := len(name)
	if nameLen > maxNameLen {
		name = name[0:maxNameLen/2] + "..." + name[nameLen-maxNameLen/2:nameLen]
	}
	message := fmt.Sprintf("%s (%d/%d)   %d/%d,%d",
		name,
		editor.fileIdx,
		len(editor.files),
		editor.file.MultiCursor[0].Row(),
		editor.file.Length()-1,
		editor.file.MultiCursor[0].Col(),
	)
	col := cols - len(message)
	editor.screen.WriteString(rows-1, col, message)
	editor.screen.WriteString(rows-1, 0, "[ Sith 0.3.2 ]")
	editor.screen.DecorateStatusLine()
	editor.file.WriteStatus(rows-1, col)
	editor.screen.SetCursor(editor.file.GetCursor(0))
}
<commit_msg>release candidate; v3.3-rc1<commit_after>package editor

import "github.com/nsf/termbox-go"
import "fmt"
import "os"
import "io/ioutil"
import "path/filepath"
import "github.com/wx13/sith/syntaxcolor"
import "github.com/wx13/sith/terminal"
import "github.com/wx13/sith/file"

type Editor struct {
	screen     *terminal.Screen
	file       *file.File
	files      []*file.File
	fileIdx    int
	fileIdxPrv int
	keyboard   *terminal.Keyboard
	flushChan  chan struct{}

	searchHist  []string
	replaceHist []string

	copyBuffer file.Buffer
	copyContig int
	copyHist   []file.Buffer
}

func NewEditor() *Editor {
	return &Editor{
		flushChan:  make(chan struct{}, 1),
		screen:     terminal.NewScreen(),
		copyBuffer: file.MakeBuffer([]string{}),
		copyContig: 0,
		copyHist:   []file.Buffer{},
	}
}

func (editor *Editor) OpenNewFile() {
	dir, _ := os.Getwd()
	dir += "/"
	names := []string{}
	idx := 0
	files := []os.FileInfo{}
	for {
		files, _ = ioutil.ReadDir(dir)
		dotdot, err := os.Stat("../")
		if err == nil {
			files = append([]os.FileInfo{dotdot}, files...)
		}
		names = []string{}
		for _, file := range files {
			if file.IsDir() {
				names = append(names, file.Name()+"/")
			} else {
				names = append(names, file.Name())
			}
		}
		menu := terminal.NewMenu(editor.screen)
		idx = menu.Choose(names)
		editor.Flush()
		if idx < 0 {
			return
		}
		chosenFile := files[idx]
		if chosenFile.IsDir() {
			dir = filepath.Clean(dir+chosenFile.Name()) + "/"
		} else {
			break
		}
	}
	cwd, _ := os.Getwd()
	chosenFile, _ := filepath.Rel(cwd, dir+names[idx])
	editor.OpenFile(chosenFile)
	editor.fileIdxPrv = editor.fileIdx
	editor.fileIdx = len(editor.files) - 1
	editor.file = editor.files[editor.fileIdx]
}

func (editor *Editor) OpenFile(name string) {
	file := file.NewFile(name, editor.flushChan, editor.screen)
	file.SyntaxRules = syntaxcolor.NewSyntaxRules(name)
	editor.files = append(editor.files, file)
}

func (editor *Editor) OpenFiles(fileNames []string) {
	for _, name := range fileNames {
		editor.OpenFile(name)
	}
	if len(editor.files) == 0 {
		editor.files = append(editor.files, file.NewFile("", editor.flushChan, editor.screen))
	}
	editor.fileIdx = 0
	editor.fileIdxPrv = 0
	editor.file = editor.files[0]
}

func (editor *Editor) Quit() {
	for _, _ = range editor.files {
		if !editor.CloseFile() {
			editor.NextFile()
		}
	}
}

func (editor *Editor) CloseFile() bool {
	editor.Flush()
	idx := editor.fileIdx
	if !editor.files[idx].Close() {
		return false
	}
	editor.files = append(editor.files[:idx], editor.files[idx+1:]...)
	if len(editor.files) == 0 {
		editor.screen.Close()
		return true
	}
	editor.NextFile()
	return true
}

func (editor *Editor) Listen() {

	keyboard := terminal.NewKeyboard()
	for {
		cmd, r := keyboard.GetKey()
		switch cmd {
		case "backspace":
			editor.file.Backspace()
		case "delete", "ctrlD":
			editor.file.Delete()
		case "space":
			editor.file.InsertChar(' ')
		case "tab":
			editor.file.InsertChar('\t')
		case "enter":
			editor.file.Newline()
		case "arrowLeft", "ctrlO":
			editor.file.CursorLeft()
		case "arrowRight", "ctrlL":
			editor.file.CursorRight()
		case "arrowUp", "ctrlK":
			editor.file.CursorUp(1)
		case "arrowDown", "ctrlJ":
			editor.file.CursorDown(1)
		case "ctrlU":
			editor.file.ScrollUp()
		case "ctrlP":
			editor.file.ScrollDown()
		case "altP":
			editor.file.ScrollRight()
		case "altU":
			editor.file.ScrollLeft()
		case "pageDown", "ctrlN":
			editor.file.PageDown()
		case "pageUp", "ctrlB":
			editor.file.PageUp()
		case "ctrlG":
			editor.file.GoToLine()
		case "altL":
			editor.file.Refresh()
		case "altO":
			editor.OpenNewFile()
		case "altQ":
			editor.Quit()
		case "altW":
			editor.CloseFile()
		case "altZ":
			editor.Suspend()
			keyboard = terminal.NewKeyboard()
		case "altN":
			editor.NextFile()
		case "altB":
			editor.PrevFile()
		case "altK":
			editor.LastFile()
		case "altM":
			editor.SelectFile()
		case "ctrlX":
			editor.file.AddCursor()
		case "altC":
			editor.file.AddCursorCol()
		case "altX":
			editor.file.ClearCursors()
		case "ctrlZ":
			editor.Undo()
		case "ctrlY":
			editor.Redo()
		case "ctrlS":
			editor.Save()
		case "ctrlA":
			editor.file.StartOfLine()
		case "ctrlE":
			editor.file.EndOfLine()
		case "ctrlW":
			editor.file.NextWord()
		case "ctrlQ":
			editor.file.PrevWord()
		case "ctrlF":
			editor.Search(false)
		case "altF":
			editor.SearchAndReplace(false)
		case "ctrlR":
			editor.Search(true)
		case "altR":
			editor.SearchAndReplace(true)
		case "ctrlC":
			editor.Cut()
		case "ctrlV":
			editor.Paste()
		case "altV":
			editor.PasteFromMenu()
		case "altG":
			editor.GoFmt()
		case "altJ":
			editor.file.Justify(72)
		case "altE":
			editor.file.Justify(0)
		case "altI":
			editor.file.ToggleAutoIndent()
		case "altT":
			editor.file.ToggleAutoTab()
		case "unknown":
			editor.screen.Notify("Unknown keypress")
		case "char":
			editor.file.InsertChar(r)
		default:
			editor.screen.Notify("Unknown keypress")
		}
		editor.copyContig--
		editor.RequestFlush()
	}

}

func (editor *Editor) Undo() {
	editor.file.Undo()
}

func (editor *Editor) Redo() {
	editor.file.Redo()
}

func (editor *Editor) NextFile() {
	editor.SwitchFile(editor.fileIdx + 1)
}

func (editor *Editor) PrevFile() {
	editor.SwitchFile(editor.fileIdx - 1)
}

func (editor *Editor) LastFile() {
	editor.SwitchFile(editor.fileIdxPrv)
}

func (editor *Editor) SelectFile() {
	names := []string{}
	for _, file := range editor.files {
		names = append(names, file.Name)
	}
	menu := terminal.NewMenu(editor.screen)
	idx := menu.Choose(names)
	if idx >= 0 {
		editor.SwitchFile(idx)
	}
}

func (editor *Editor) Save() {
	filetype := editor.file.SyntaxRules.GetFileType(editor.file.Name)
	if filetype == "go" {
		editor.GoFmt()
	}
	editor.file.RequestSave()
}

func (editor *Editor) GoFmt() {
	err := editor.file.GoFmt()
	if err == nil {
		editor.RequestFlush()
		editor.file.NotifyUser("GoFmt done")
	} else {
		editor.file.NotifyUser(err.Error())
	}
}

func intMod(a, n int) int {
	if a >= 0 {
		return a - n*(a/n)
	} else {
		return a - n*((a-n+1)/n)
	}
}

func (editor *Editor) SwitchFile(n int) {
	n = intMod(n, len(editor.files))
	editor.fileIdxPrv = editor.fileIdx
	editor.fileIdx = n
	editor.file = editor.files[n]
}

func (editor *Editor) HighlightCursors() {
	cells := termbox.CellBuffer()
	cols, _ := termbox.Size()
	for k, _ := range editor.file.MultiCursor[1:] {
		r, c := editor.file.GetCursor(k + 1)
		j := r*cols + c
		if j < 0 || j >= len(cells) {
			continue
		}
		cells[j].Bg |= termbox.AttrReverse
		cells[j].Fg |= termbox.AttrReverse
	}
}

func (editor *Editor) Flush() {
	editor.file.Flush()
	editor.HighlightCursors()
	editor.UpdateStatus()
	editor.screen.Flush()
}

func (editor *Editor) KeepFlushed() {
	go func() {
		for {
			<-editor.flushChan
			editor.Flush()
		}
	}()
}

func (editor *Editor) RequestFlush() {
	select {
	case editor.flushChan <- struct{}{}:
	default:
	}
}

func (editor *Editor) UpdateStatus() {
	cols, rows := termbox.Size()
	maxNameLen := cols / 3
	name := editor.file.Name
	nameLen := len(name)
	if nameLen > maxNameLen {
		name = name[0:maxNameLen/2] + "..." + name[nameLen-maxNameLen/2:nameLen]
	}
	message := fmt.Sprintf("%s (%d/%d)   %d/%d,%d",
		name,
		editor.fileIdx,
		len(editor.files),
		editor.file.MultiCursor[0].Row(),
		editor.file.Length()-1,
		editor.file.MultiCursor[0].Col(),
	)
	col := cols - len(message)
	editor.screen.WriteString(rows-1, col, message)
	editor.screen.WriteString(rows-1, 0, "[ Sith 0.3.3-rc1 ]")
	editor.screen.DecorateStatusLine()
	editor.file.WriteStatus(rows-1, col)
	editor.screen.SetCursor(editor.file.GetCursor(0))
}
<|endoftext|>


<commit_before>package editor

import (
	"github.com/elpinal/coco3/complete"
	"github.com/elpinal/coco3/config"
	"github.com/elpinal/coco3/screen"
)

type insert struct {
	streamSet
	*editor
	s    screen.Screen
	conf *config.Config

	needSave bool

	replaceMode bool
	replacedBuf []rune
}

func (e *insert) Mode() mode {
	return modeInsert
}

func (e *insert) Run() (end bool, next mode, err error) {
	next = modeInsert
	if e.replaceMode {
		next = modeReplace
	}
	r, _, err := e.streamSet.in.ReadRune()
	if err != nil {
		return end, next, err
	}
start:
	switch r {
	case CharEscape:
		if e.replaceMode {
			e.buf = e.overwrite(e.replacedBuf, e.buf, e.pos-len(e.buf))
		}
		e.move(e.pos - 1)
		next = modeNormal
		if e.needSave {
			e.undoTree.add(e.buf)
		}
	case CharBackspace, CharCtrlH:
		e.deleteChar()
		e.needSave = true
	case CharCtrlM:
		end = true
		e.needSave = true
	case CharCtrlX:
		r1, _, err := e.streamSet.in.ReadRune()
		if err != nil {
			return end, next, err
		}
		r2, err := e.ctrlX(r1)
		if err != nil {
			return end, next, err
		}
		r = r2
		goto start
	case CharCtrlW:
		e.deleteWord()
		e.needSave = true
	default:
		e.insert([]rune{r}, e.pos)
		e.needSave = true
	}
	return end, next, err
}

func (e *insert) Runes() []rune {
	if e.replaceMode {
		return e.overwrite(e.replacedBuf, e.editor.buf, e.editor.pos-len(e.buf))
	}
	return e.editor.buf
}

func (e *insert) Position() int {
	return e.editor.pos
}

func (e *insert) ctrlX(r rune) (rune, error) {
	var f func([]rune, int) ([]string, error)
	switch r {
	case CharCtrlF:
		f = complete.File
	default:
		return r, nil
	}

	list, err := f(e.buf, e.pos)
	if err != nil {
		return 0, err
	}
	list = append(list, "")
	e.insert([]rune(list[0]), e.pos)
	e.needSave = true
	n := 0
	for {
		e.s.Refresh(e.conf, e.buf, e.pos)
		r1, _, err := e.streamSet.in.ReadRune()
		if err != nil {
			return 0, err
		}
		n1 := n
		switch r1 {
		case CharCtrlN, r:
			n++
			if len(list) <= n {
				n = 0
			}
		case CharCtrlP:
			n--
			if n < 0 {
				n = len(list) - 1
			}
		case CharCtrlY:
			r2, _, err := e.streamSet.in.ReadRune()
			return r2, err
		case CharCtrlE:
			e.delete(e.pos, e.pos-len(list[n1]))
			e.s.Refresh(e.conf, e.buf, e.pos)
			r2, _, err := e.streamSet.in.ReadRune()
			return r2, err
		default:
			return r1, nil
		}
		e.delete(e.pos, e.pos-len(list[n1]))
		e.insert([]rune(list[n]), e.pos)
	}
}

func (e *insert) deleteChar() {
	if !e.replaceMode {
		e.delete(e.pos-1, e.pos)
		return
	}
	if e.pos == 0 {
		return
	}
	e.pos--
	if len(e.buf) > 0 {
		e.buf = e.buf[:len(e.buf)-1]
		return
	}
}

func (e *insert) deleteWord() {
	if !e.replaceMode {
		pos := e.pos
		e.wordBackward()
		e.delete(pos, e.pos)
		return
	}
	if e.pos == 0 {
		return
	}
	off := e.pos - len(e.buf)
	e.pos -= off
	pos := e.pos
	e.wordBackward()
	if len(e.buf) > 0 {
		e.delete(pos, e.pos)
		e.pos += off
	}
}
<commit_msg>Support i_CTRL-U<commit_after>package editor

import (
	"github.com/elpinal/coco3/complete"
	"github.com/elpinal/coco3/config"
	"github.com/elpinal/coco3/screen"
)

type insert struct {
	streamSet
	*editor
	s    screen.Screen
	conf *config.Config

	needSave bool

	replaceMode bool
	replacedBuf []rune
}

func (e *insert) Mode() mode {
	return modeInsert
}

func (e *insert) Run() (end bool, next mode, err error) {
	next = modeInsert
	if e.replaceMode {
		next = modeReplace
	}
	r, _, err := e.streamSet.in.ReadRune()
	if err != nil {
		return end, next, err
	}
start:
	switch r {
	case CharEscape:
		if e.replaceMode {
			e.buf = e.overwrite(e.replacedBuf, e.buf, e.pos-len(e.buf))
		}
		e.move(e.pos - 1)
		next = modeNormal
		if e.needSave {
			e.undoTree.add(e.buf)
		}
	case CharBackspace, CharCtrlH:
		e.deleteChar()
		e.needSave = true
	case CharCtrlM:
		end = true
		e.needSave = true
	case CharCtrlX:
		r1, _, err := e.streamSet.in.ReadRune()
		if err != nil {
			return end, next, err
		}
		r2, err := e.ctrlX(r1)
		if err != nil {
			return end, next, err
		}
		r = r2
		goto start
	case CharCtrlW:
		e.deleteWord()
		e.needSave = true
	case CharCtrlU:
		e.deleteToBeginning()
		e.needSave = true
	default:
		e.insert([]rune{r}, e.pos)
		e.needSave = true
	}
	return end, next, err
}

func (e *insert) Runes() []rune {
	if e.replaceMode {
		return e.overwrite(e.replacedBuf, e.editor.buf, e.editor.pos-len(e.buf))
	}
	return e.editor.buf
}

func (e *insert) Position() int {
	return e.editor.pos
}

func (e *insert) ctrlX(r rune) (rune, error) {
	var f func([]rune, int) ([]string, error)
	switch r {
	case CharCtrlF:
		f = complete.File
	default:
		return r, nil
	}

	list, err := f(e.buf, e.pos)
	if err != nil {
		return 0, err
	}
	list = append(list, "")
	e.insert([]rune(list[0]), e.pos)
	e.needSave = true
	n := 0
	for {
		e.s.Refresh(e.conf, e.buf, e.pos)
		r1, _, err := e.streamSet.in.ReadRune()
		if err != nil {
			return 0, err
		}
		n1 := n
		switch r1 {
		case CharCtrlN, r:
			n++
			if len(list) <= n {
				n = 0
			}
		case CharCtrlP:
			n--
			if n < 0 {
				n = len(list) - 1
			}
		case CharCtrlY:
			r2, _, err := e.streamSet.in.ReadRune()
			return r2, err
		case CharCtrlE:
			e.delete(e.pos, e.pos-len(list[n1]))
			e.s.Refresh(e.conf, e.buf, e.pos)
			r2, _, err := e.streamSet.in.ReadRune()
			return r2, err
		default:
			return r1, nil
		}
		e.delete(e.pos, e.pos-len(list[n1]))
		e.insert([]rune(list[n]), e.pos)
	}
}

func (e *insert) deleteChar() {
	if !e.replaceMode {
		e.delete(e.pos-1, e.pos)
		return
	}
	if e.pos == 0 {
		return
	}
	e.pos--
	if len(e.buf) > 0 {
		e.buf = e.buf[:len(e.buf)-1]
		return
	}
}

func (e *insert) deleteWord() {
	if !e.replaceMode {
		pos := e.pos
		e.wordBackward()
		e.delete(pos, e.pos)
		return
	}
	if e.pos == 0 {
		return
	}
	off := e.pos - len(e.buf)
	e.pos -= off
	pos := e.pos
	e.wordBackward()
	if len(e.buf) > 0 {
		e.delete(pos, e.pos)
		e.pos += off
	}
}

func (e *insert) deleteToBeginning() {
	if !e.replaceMode {
		e.delete(0, e.pos)
		return
	}
	if e.pos == 0 {
		return
	}
	off := e.pos - len(e.buf)
	e.pos -= off
	if len(e.buf) > 0 {
		e.delete(0, e.pos)
		e.pos += off
	}
}
<|endoftext|>


<commit_before>package espsdk

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

// A Batch is a container for Contributions of the same type and
// any Releases that may be associated with them.
type Batch struct {
	AssignmentID                     string     `json:"assignment_id,omitempty"`
	BatchTags                        []string   `json:"batch_tags,omitempty"`
	BriefID                          string     `json:"brief_id,omitempty"`
	ContributionsAwaitingReviewCount int        `json:"contributions_awaiting_review_count,omitempty"`
	ContributionsCount               int        `json:"contributions_count,omitempty"`
	CreatedAt                        *time.Time `json:"created_at,omitempty"`
	CreatedBy                        string     `json:"created_by,omitempty"`
	CreatorIstockUsername            string     `json:"creator_istock_username,omitempty"`
	EventID                          string     `json:"event_id,omitempty"`
	ID                               int        `json:"id,omitempty"`
	IsGetty                          bool       `json:"is_getty,omitempty"`
	IsIstock                         bool       `json:"is_istock,omitempty"`
	IstockExclusive                  bool       `json:"istock_exclusive,omitempty"`
	LastContributionSubmittedAt      *time.Time `json:"last_contribution_submitted_at,omitempty"`
	LastSubmittedAt                  *time.Time `json:"last_submitted_at,omitempty"`
	Note                             string     `json:"note,omitempty"`
	ProfileID                        int        `json:"profile_id,omitempty"`
	ReviewedContributionsCount       int        `json:"reviewed_contributions_count,omitempty"`
	RevisableContributionsCount      int        `json:"revisable_contributions_count,omitempty"`
	SaveExtractedMetadata            bool       `json:"save_extracted_metadata,omitempty"`
	Status                           string     `json:"status,omitempty"`
	SubmissionName                   string     `json:"submission_name,omitempty"`
	SubmissionType                   string     `json:"submission_type,omitempty"`
	SubmittedContributionsCount      int        `json:"submitted_contributions_count,omitempty"`
	UpdatedAt                        *time.Time `json:"updated_at,omitempty"`
	UserID                           string     `json:"user_id,omitempty"`
}

// NameIsValid provides validation for a proposed SubmissionName.
func (b Batch) NameIsValid() bool { return len(b.SubmissionName) > 0 }

// TypeIsValid reports whether a proposed type is valid for ESP.
func (b *Batch) TypeIsValid() bool { return batchTypeIsValid[b.SubmissionType] }

// ValidTypes are the BatchTypes supported by ESP.
func (b Batch) ValidTypes() []string {
	keys := make([]string, len(batchTypeIsValid))
	i := 0
	for k := range batchTypeIsValid {
		keys[i] = k
		i++
	}
	return keys
}

// Path returns the path for the Batch. If the Batch has no ID, Path returns
// the root for all Batches (the Batch Index).
func (b Batch) Path() string {
	if b.ID == 0 {
		return Batches
	}
	return fmt.Sprintf("%s/%d", Batches, b.ID)
}

// Marshal serializes the Batch into a byte slice.
func (b Batch) Marshal() ([]byte, error) { return indentedJSON(b) }

// Unmarshal serializes the Batch into a byte slice.
func (b Batch) Unmarshal(payload []byte) (*Batch, error) {
	var batch *Batch
	err := json.Unmarshal(payload, &batch)
	if err != nil {
		return batch, err
	}
	return batch, nil
}

// A BatchUpdate contains a Batch. This matches the
// structure of the JSON payload the API expects during a PUT.
type BatchUpdate struct {
	Batch Batch `json:"submission_batch"`
}

// Path returns the path of the batch being updated.
func (bu BatchUpdate) Path() string { return bu.Batch.Path() }

// Marshal serializes a BatchUpdate into a byte slice.
func (bu BatchUpdate) Marshal() ([]byte, error) { return indentedJSON(bu) }

var batchTypeIsValid = map[string]bool{
	"getty_creative_video":  true,
	"getty_editorial_video": true,
	"getty_creative_still":  true,
	"getty_editorial_still": true,
	"istock_creative_video": true,
}

// A BatchList matches the structure of the JSON payload returned
// by the GET (all) Batches API endpoint.
type BatchList struct {
	Items []Batch `json:"items,omitempty"`
	Meta  struct {
		TotalItems int `json:"total_items,omitempty"`
	} `json:"meta,omitempty"`
}

// Unmarshal attempts to deserialize the provided JSON payload
// into the complete metadata returned by a request to the Index (GET all)
// API endpoint.
func (bl BatchList) Unmarshal(payload []byte) BatchList {
	var dest BatchList
	err := json.Unmarshal(payload, &dest)
	if err != nil {
		log.Error(err)
	}
	return dest
}

// Last returns the most recently-created batch.
func (bl BatchList) Last() Batch {
	log.Debugf("getting last of %d batches", bl.Meta.TotalItems)
	return bl.Items[len(bl.Items)-1]
}
<commit_msg>fix: respect that API returns newest-first list of Batches<commit_after>package espsdk

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

// A Batch is a container for Contributions of the same type and
// any Releases that may be associated with them.
type Batch struct {
	AssignmentID                     string     `json:"assignment_id,omitempty"`
	BatchTags                        []string   `json:"batch_tags,omitempty"`
	BriefID                          string     `json:"brief_id,omitempty"`
	ContributionsAwaitingReviewCount int        `json:"contributions_awaiting_review_count,omitempty"`
	ContributionsCount               int        `json:"contributions_count,omitempty"`
	CreatedAt                        *time.Time `json:"created_at,omitempty"`
	CreatedBy                        string     `json:"created_by,omitempty"`
	CreatorIstockUsername            string     `json:"creator_istock_username,omitempty"`
	EventID                          string     `json:"event_id,omitempty"`
	ID                               int        `json:"id,omitempty"`
	IsGetty                          bool       `json:"is_getty,omitempty"`
	IsIstock                         bool       `json:"is_istock,omitempty"`
	IstockExclusive                  bool       `json:"istock_exclusive,omitempty"`
	LastContributionSubmittedAt      *time.Time `json:"last_contribution_submitted_at,omitempty"`
	LastSubmittedAt                  *time.Time `json:"last_submitted_at,omitempty"`
	Note                             string     `json:"note,omitempty"`
	ProfileID                        int        `json:"profile_id,omitempty"`
	ReviewedContributionsCount       int        `json:"reviewed_contributions_count,omitempty"`
	RevisableContributionsCount      int        `json:"revisable_contributions_count,omitempty"`
	SaveExtractedMetadata            bool       `json:"save_extracted_metadata,omitempty"`
	Status                           string     `json:"status,omitempty"`
	SubmissionName                   string     `json:"submission_name,omitempty"`
	SubmissionType                   string     `json:"submission_type,omitempty"`
	SubmittedContributionsCount      int        `json:"submitted_contributions_count,omitempty"`
	UpdatedAt                        *time.Time `json:"updated_at,omitempty"`
	UserID                           string     `json:"user_id,omitempty"`
}

// NameIsValid provides validation for a proposed SubmissionName.
func (b Batch) NameIsValid() bool { return len(b.SubmissionName) > 0 }

// TypeIsValid reports whether a proposed type is valid for ESP.
func (b *Batch) TypeIsValid() bool { return batchTypeIsValid[b.SubmissionType] }

// ValidTypes are the BatchTypes supported by ESP.
func (b Batch) ValidTypes() []string {
	keys := make([]string, len(batchTypeIsValid))
	i := 0
	for k := range batchTypeIsValid {
		keys[i] = k
		i++
	}
	return keys
}

// Path returns the path for the Batch. If the Batch has no ID, Path returns
// the root for all Batches (the Batch Index).
func (b Batch) Path() string {
	if b.ID == 0 {
		return Batches
	}
	return fmt.Sprintf("%s/%d", Batches, b.ID)
}

// Marshal serializes the Batch into a byte slice.
func (b Batch) Marshal() ([]byte, error) { return indentedJSON(b) }

// Unmarshal serializes the Batch into a byte slice.
func (b Batch) Unmarshal(payload []byte) (*Batch, error) {
	var batch *Batch
	err := json.Unmarshal(payload, &batch)
	if err != nil {
		return batch, err
	}
	return batch, nil
}

// A BatchUpdate contains a Batch. This matches the
// structure of the JSON payload the API expects during a PUT.
type BatchUpdate struct {
	Batch Batch `json:"submission_batch"`
}

// Path returns the path of the batch being updated.
func (bu BatchUpdate) Path() string { return bu.Batch.Path() }

// Marshal serializes a BatchUpdate into a byte slice.
func (bu BatchUpdate) Marshal() ([]byte, error) { return indentedJSON(bu) }

var batchTypeIsValid = map[string]bool{
	"getty_creative_video":  true,
	"getty_editorial_video": true,
	"getty_creative_still":  true,
	"getty_editorial_still": true,
	"istock_creative_video": true,
}

// A BatchList matches the structure of the JSON payload returned
// by the GET (all) Batches API endpoint.
type BatchList struct {
	Items []Batch `json:"items,omitempty"`
	Meta  struct {
		TotalItems int `json:"total_items,omitempty"`
	} `json:"meta,omitempty"`
}

// Unmarshal attempts to deserialize the provided JSON payload
// into the complete metadata returned by a request to the Index (GET all)
// API endpoint.
func (bl BatchList) Unmarshal(payload []byte) BatchList {
	var dest BatchList
	err := json.Unmarshal(payload, &dest)
	if err != nil {
		log.Error(err)
	}
	return dest
}

// Last returns the most recently-created batch.
func (bl BatchList) Last() Batch {
	log.Debugf("getting last of %d batches", bl.Meta.TotalItems)
	return bl.Items[0]
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"regexp"

	"github.com/codegangsta/cli"
	"github.com/dronemill/harmony-client-go"
	"github.com/olekukonko/tablewriter"
)

// Baton is the main app contianer
type Baton struct {
	// the cli app
	App *cli.App

	// hamrony client
	Harmony *harmonyclient.Client
}

// maestroConnect will get a connected maestro client
func (b *Baton) maestroConnect(c *cli.Context) error {
	config := harmonyclient.Config{
		APIHost:      c.String("harmony-api"),
		APIVersion:   "v1",
		APIVerifySSL: !c.Bool("noverifyssl"),
	}

	var err error
	b.Harmony, err = harmonyclient.NewHarmonyClient(config)

	if err != nil {
		return fmt.Errorf(fmt.Sprintf("Failed connecting to the maestro: %s", err.Error()))
	}

	return nil
}

// Containers will show help for the contianers section of the app
func (b *Baton) Containers(c *cli.Context) {
	cli.ShowAppHelp(c)
}

// Machines will show help for the contianers section of the app
func (b *Baton) Machines(c *cli.Context) {
	cli.ShowAppHelp(c)
}

// ContainersAdd will add a container
func (b *Baton) ContainersAdd(c *cli.Context) {
	if err := b.maestroConnect(c); err != nil {
		fmt.Printf("%s\n\n", err.Error())
		return
	}

	machineID := c.String("machine-id")
	if machineID == "" {
		fmt.Println("machine-id is required")
		return
	}

	name := c.String("name")
	if name == "" {
		fmt.Println("name is required")
		return
	}

	hostname := c.String("hostname")
	if hostname == "" {
		fmt.Println("hostname is required")
		return
	}

	image := c.String("image")
	if image == "" {
		fmt.Println("image is required")
		return
	}

	entryPoint := c.String("entry-point")

	cntr := &harmonyclient.Container{
		MachineID:  machineID,
		Name:       name,
		Hostname:   hostname,
		Image:      image,
		EntryPoint: entryPoint,
	}

	newCntr, err := b.Harmony.ContainersAdd(cntr)

	if err != nil {
		fmt.Printf("Error encountered while attempting to create new container: %s\n", err.Error())
		return
	}

	fmt.Printf("%s\n", newCntr.ID)
}

// ContainersShow will show containers
func (b *Baton) ContainersShow(c *cli.Context) {
	if err := b.maestroConnect(c); err != nil {
		fmt.Printf("%s\n\n", err.Error())
		return
	}

	ctrs, err := b.Harmony.Containers()

	if err != nil {
		fmt.Printf("GOT ERROR: %s\n", err.Error())
		return
	}

	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"ID", "Name", "Hostname", "MachineID", "CID"})

	for _, v := range *ctrs {
		r := []string{
			v.ID,
			v.Name,
			v.Hostname,
			v.MachineID,
			v.CID,
		}

		table.Append(r)
	}

	fmt.Println()
	table.SetBorder(false)
	table.Render() // Send output
}

// MachinesShow will show machines
func (b *Baton) MachinesShow(c *cli.Context) {
	if err := b.maestroConnect(c); err != nil {
		fmt.Printf("%s\n\n", err.Error())
		return
	}

	if len(c.Args()) == 0 {
		b.showMachines(c)
		return
	}

	machineID := c.Args()[0]
	if matched, _ := regexp.MatchString("^[0-9]*$", machineID); matched {
		b.showMachineByID(c, machineID)
	} else {
		b.showMachineByName(c, machineID)
	}
}

// showMachines is the command processor for showing all machines
func (b *Baton) showMachines(c *cli.Context) {
	machines, err := b.Harmony.Machines()

	if err != nil {
		fmt.Printf("GOT ERROR: %s\n", err.Error())
		return
	}

	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"ID", "Name", "Hostname"})

	for _, v := range *machines {
		r := []string{
			v.ID,
			v.Name,
			v.Hostname,
		}

		table.Append(r)
	}

	fmt.Println()
	table.SetBorder(false)
	table.Render() // Send output
}

// showMachineByID will show a machine by its id
func (b *Baton) showMachineByID(c *cli.Context, ID string) {
	m, err := b.Harmony.Machine(ID)

	if err != nil {
		fmt.Printf("GOT ERROR: %s\n", err.Error())
		return
	}

	if m == nil {
		fmt.Printf("ERROR: machineID '%s' not found\n", ID)
		return
	}

	b.renderMachine(c, m)
}

// showMachineByName will show a machine by its name
func (b *Baton) showMachineByName(c *cli.Context, name string) {
	m, err := b.Harmony.MachineByName(name)

	if err != nil {
		fmt.Printf("GOT ERROR: %s\n", err.Error())
		return
	}

	if m == nil {
		fmt.Printf("ERROR: machine with name '%s' not found\n", name)
		return
	}

	b.renderMachine(c, m)

}

// renderMachine will output a formatted machine
func (b *Baton) renderMachine(c *cli.Context, m *harmonyclient.Machine) {
	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"ID", "Name", "Hostname"})

	r := []string{
		m.ID,
		m.Name,
		m.Hostname,
	}
	table.Append(r)

	fmt.Println()
	table.SetBorder(false)
	table.Render() // Send output

	table = tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"Containers"})
	for _, v := range m.ContainerIDs {
		r := []string{
			v,
		}

		table.Append(r)
	}

	fmt.Println()
	table.SetBorder(false)
	table.Render() // Send output

}
<commit_msg>Fix out of band index when no CID exists on a container<commit_after>package main

import (
	"fmt"
	"os"
	"regexp"

	"github.com/codegangsta/cli"
	"github.com/dronemill/harmony-client-go"
	"github.com/olekukonko/tablewriter"
)

// Baton is the main app contianer
type Baton struct {
	// the cli app
	App *cli.App

	// hamrony client
	Harmony *harmonyclient.Client
}

// maestroConnect will get a connected maestro client
func (b *Baton) maestroConnect(c *cli.Context) error {
	config := harmonyclient.Config{
		APIHost:      c.String("harmony-api"),
		APIVersion:   "v1",
		APIVerifySSL: !c.Bool("noverifyssl"),
	}

	var err error
	b.Harmony, err = harmonyclient.NewHarmonyClient(config)

	if err != nil {
		return fmt.Errorf(fmt.Sprintf("Failed connecting to the maestro: %s", err.Error()))
	}

	return nil
}

// Containers will show help for the contianers section of the app
func (b *Baton) Containers(c *cli.Context) {
	cli.ShowAppHelp(c)
}

// Machines will show help for the contianers section of the app
func (b *Baton) Machines(c *cli.Context) {
	cli.ShowAppHelp(c)
}

// ContainersAdd will add a container
func (b *Baton) ContainersAdd(c *cli.Context) {
	if err := b.maestroConnect(c); err != nil {
		fmt.Printf("%s\n\n", err.Error())
		return
	}

	machineID := c.String("machine-id")
	if machineID == "" {
		fmt.Println("machine-id is required")
		return
	}

	name := c.String("name")
	if name == "" {
		fmt.Println("name is required")
		return
	}

	hostname := c.String("hostname")
	if hostname == "" {
		fmt.Println("hostname is required")
		return
	}

	image := c.String("image")
	if image == "" {
		fmt.Println("image is required")
		return
	}

	entryPoint := c.String("entry-point")

	cntr := &harmonyclient.Container{
		MachineID:  machineID,
		Name:       name,
		Hostname:   hostname,
		Image:      image,
		EntryPoint: entryPoint,
	}

	newCntr, err := b.Harmony.ContainersAdd(cntr)

	if err != nil {
		fmt.Printf("Error encountered while attempting to create new container: %s\n", err.Error())
		return
	}

	fmt.Printf("%s\n", newCntr.ID)
}

// ContainersShow will show containers
func (b *Baton) ContainersShow(c *cli.Context) {
	if err := b.maestroConnect(c); err != nil {
		fmt.Printf("%s\n\n", err.Error())
		return
	}

	ctrs, err := b.Harmony.Containers()

	if err != nil {
		fmt.Printf("GOT ERROR: %s\n", err.Error())
		return
	}

	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"ID", "Name", "Hostname", "MachineID", "CID"})

	for _, v := range *ctrs {
		cid := v.CID
		if len(cid) > 12 {
			cid = v.CID[0:12]
		}
		r := []string{
			v.ID,
			v.Name,
			v.Hostname,
			v.MachineID,
			cid,
		}

		table.Append(r)
	}

	fmt.Println()
	table.SetBorder(false)
	table.Render() // Send output
}

// MachinesShow will show machines
func (b *Baton) MachinesShow(c *cli.Context) {
	if err := b.maestroConnect(c); err != nil {
		fmt.Printf("%s\n\n", err.Error())
		return
	}

	if len(c.Args()) == 0 {
		b.showMachines(c)
		return
	}

	machineID := c.Args()[0]
	if matched, _ := regexp.MatchString("^[0-9]*$", machineID); matched {
		b.showMachineByID(c, machineID)
	} else {
		b.showMachineByName(c, machineID)
	}
}

// showMachines is the command processor for showing all machines
func (b *Baton) showMachines(c *cli.Context) {
	machines, err := b.Harmony.Machines()

	if err != nil {
		fmt.Printf("GOT ERROR: %s\n", err.Error())
		return
	}

	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"ID", "Name", "Hostname"})

	for _, v := range *machines {
		r := []string{
			v.ID,
			v.Name,
			v.Hostname,
		}

		table.Append(r)
	}

	fmt.Println()
	table.SetBorder(false)
	table.Render() // Send output
}

// showMachineByID will show a machine by its id
func (b *Baton) showMachineByID(c *cli.Context, ID string) {
	m, err := b.Harmony.Machine(ID)

	if err != nil {
		fmt.Printf("GOT ERROR: %s\n", err.Error())
		return
	}

	if m == nil {
		fmt.Printf("ERROR: machineID '%s' not found\n", ID)
		return
	}

	b.renderMachine(c, m)
}

// showMachineByName will show a machine by its name
func (b *Baton) showMachineByName(c *cli.Context, name string) {
	m, err := b.Harmony.MachineByName(name)

	if err != nil {
		fmt.Printf("GOT ERROR: %s\n", err.Error())
		return
	}

	if m == nil {
		fmt.Printf("ERROR: machine with name '%s' not found\n", name)
		return
	}

	b.renderMachine(c, m)

}

// renderMachine will output a formatted machine
func (b *Baton) renderMachine(c *cli.Context, m *harmonyclient.Machine) {
	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"ID", "Name", "Hostname"})

	r := []string{
		m.ID,
		m.Name,
		m.Hostname,
	}
	table.Append(r)

	fmt.Println()
	table.SetBorder(false)
	table.Render() // Send output

	table = tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"Containers"})
	for _, v := range m.ContainerIDs {
		r := []string{
			v,
		}

		table.Append(r)
	}

	fmt.Println()
	table.SetBorder(false)
	table.Render() // Send output

}
<|endoftext|>


<commit_before>// +build linux
package blink

import (
	"io"
	"log"
	"os"
	"syscall"
	"time"

	"github.com/pkg/errors"
)

const device = "/dev/console"

// ioctl is a helper function for calling syscalls
// Thanks Dave Cheney, what a guy!:
//     https://github.com/davecheney/pcap/blob/10760a170da6335ec1a48be06a86f494b0ef74ab/bpf.go#L45
func ioctl(fd int, request, argp uintptr) error {
	_, _, errorp := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), request, argp)
	return os.NewSyscallError("ioctl", errorp)
}

// Do will turn on the keyboard lights for the given amount of time. Yes ALL
// the keyboard lights.
func Do(onLen time.Duration) error {
	// ya this is probably not safe, cause I ported this to Go from Python
	// using four year old go code about how to make ioctl calls in go (btw the
	// below code is probably SUPER unsafe).
	console_fd, err := syscall.Open(device, os.O_RDONLY|syscall.O_CLOEXEC, 0666)
	defer func() {
		if err := syscall.Close(console_fd); err != nil {
			log.Printf("Failed to close file descriptor for /dev/console, fd %v", console_fd)
		}
	}()
	if err != nil {
		return errors.Wrapf(err, "cannot open %q using syscall \"O_RDONLY|O_CLOEXEC 0666\"", device)
	}

	// google it dawg
	KDSETLED := 0x4B32

	SCR_LED := 0x01
	NUM_LED := 0x02
	CAP_LED := 0x04

	all_on := SCR_LED | NUM_LED | CAP_LED
	all_off := 0
	ioctl(console_fd, uintptr(KDSETLED), uintptr(all_on))
	time.Sleep(onLen)
	ioctl(console_fd, uintptr(KDSETLED), uintptr(all_off))

	return nil
}

// DoOnDelim will call blink for duration every time a delimiter is read on
// the reader and will not blink for at least that duration.
func DoOnDelim(duration time.Duration, r io.Reader, delimiter string) error {
	delim := []byte(delimiter)
	dpos := 0
	buf := make([]byte, 1)
	for {
		_, err := r.Read(buf)
		if err == io.EOF {
			break
		}
		if err != nil {
			return errors.Wrap(err, "cannot continue reading input")
		}
		if buf[0] == delim[dpos] {
			// We found the delimiter guys, do the blink!
			if dpos == len(delim)-1 {
				dpos = 0
				if err := Do(duration); err != nil {
					return err
				}
				time.Sleep(duration)
			} else {
				dpos += 1
			}
		} else {
			dpos = 0
		}
	}

	return nil
}
<commit_msg>Correctly handle errors from syscall.Syscall<commit_after>// +build linux
package blink

import (
	"io"
	"log"
	"os"
	"syscall"
	"time"

	"github.com/pkg/errors"
)

const device = "/dev/console"

// ioctl is a helper function for calling syscalls
// Thanks Dave Cheney, what a guy!:
//     https://github.com/davecheney/pcap/blob/10760a170da6335ec1a48be06a86f494b0ef74ab/bpf.go#L45
func ioctl(fd int, request, argp uintptr) error {
	_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), request, argp)
	if errno != 0 {
		return os.NewSyscallError("ioctl", errno)
	}
	return nil
}

// Do will turn on the keyboard lights for the given amount of time. Yes ALL
// the keyboard lights.
func Do(onLen time.Duration) error {
	// ya this is probably not safe, cause I ported this to Go from Python
	// using four year old go code about how to make ioctl calls in go (btw the
	// below code is probably SUPER unsafe).
	console_fd, err := syscall.Open(device, os.O_RDONLY|syscall.O_CLOEXEC, 0666)
	defer func() {
		if err := syscall.Close(console_fd); err != nil {
			log.Printf("Failed to close file descriptor for /dev/console, fd %v", console_fd)
		}
	}()
	if err != nil {
		return errors.Wrapf(err, "cannot open %q using syscall \"O_RDONLY|O_CLOEXEC 0666\"", device)
	}

	// google it dawg
	KDSETLED := 0x4B32

	SCR_LED := 0x01
	NUM_LED := 0x02
	CAP_LED := 0x04

	all_on := SCR_LED | NUM_LED | CAP_LED
	all_off := 0
	ioctl(console_fd, uintptr(KDSETLED), uintptr(all_on))
	time.Sleep(onLen)
	ioctl(console_fd, uintptr(KDSETLED), uintptr(all_off))

	return nil
}

// DoOnDelim will call blink for duration every time a delimiter is read on
// the reader and will not blink for at least that duration.
func DoOnDelim(duration time.Duration, r io.Reader, delimiter string) error {
	delim := []byte(delimiter)
	dpos := 0
	buf := make([]byte, 1)
	for {
		_, err := r.Read(buf)
		if err == io.EOF {
			break
		}
		if err != nil {
			return errors.Wrap(err, "cannot continue reading input")
		}
		if buf[0] == delim[dpos] {
			// We found the delimiter guys, do the blink!
			if dpos == len(delim)-1 {
				dpos = 0
				if err := Do(duration); err != nil {
					return err
				}
				time.Sleep(duration)
			} else {
				dpos += 1
			}
		} else {
			dpos = 0
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package terraform

import (
	"fmt"

	"github.com/hashicorp/go-version"
)

// The main version number that is being run at the moment.
const Version = "0.10.1"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
var VersionPrerelease = "dev"

// SemVersion is an instance of version.Version. This has the secondary
// benefit of verifying during tests and init time that our version is a
// proper semantic version, which should always be the case.
var SemVersion = version.Must(version.NewVersion(Version))

// VersionHeader is the header name used to send the current terraform version
// in http requests.
const VersionHeader = "Terraform-Version"

func VersionString() string {
	if VersionPrerelease != "" {
		return fmt.Sprintf("%s-%s", Version, VersionPrerelease)
	}
	return Version
}
<commit_msg>v0.10.1<commit_after>package terraform

import (
	"fmt"

	"github.com/hashicorp/go-version"
)

// The main version number that is being run at the moment.
const Version = "0.10.1"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
var VersionPrerelease = ""

// SemVersion is an instance of version.Version. This has the secondary
// benefit of verifying during tests and init time that our version is a
// proper semantic version, which should always be the case.
var SemVersion = version.Must(version.NewVersion(Version))

// VersionHeader is the header name used to send the current terraform version
// in http requests.
const VersionHeader = "Terraform-Version"

func VersionString() string {
	if VersionPrerelease != "" {
		return fmt.Sprintf("%s-%s", Version, VersionPrerelease)
	}
	return Version
}
<|endoftext|>


<commit_before>// run

// Copyright 2009 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.

// Test heap sampling logic.

package main

import (
	"fmt"
	"math"
	"runtime"
)

var a16 *[16]byte
var a512 *[512]byte
var a256 *[256]byte
var a1k *[1024]byte
var a64k *[64 * 1024]byte

// This test checks that heap sampling produces reasonable
// results. Note that heap sampling uses randomization, so the results
// vary for run to run. This test only checks that the resulting
// values appear reasonable.
func main() {
	const countInterleaved = 10000
	allocInterleaved(countInterleaved)
	checkAllocations(getMemProfileRecords(), "main.allocInterleaved", countInterleaved, []int64{256 * 1024, 1024, 256 * 1024, 512, 256 * 1024, 256})

	const count = 100000
	alloc(count)
	checkAllocations(getMemProfileRecords(), "main.alloc", count, []int64{1024, 512, 256})
}

// allocInterleaved stress-tests the heap sampling logic by
// interleaving large and small allocations.
func allocInterleaved(n int) {
	for i := 0; i < n; i++ {
		// Test verification depends on these lines being contiguous.
		a64k = new([64 * 1024]byte)
		a1k = new([1024]byte)
		a64k = new([64 * 1024]byte)
		a512 = new([512]byte)
		a64k = new([64 * 1024]byte)
		a256 = new([256]byte)
	}
}

// alloc performs only small allocations for sanity testing.
func alloc(n int) {
	for i := 0; i < n; i++ {
		// Test verification depends on these lines being contiguous.
		a1k = new([1024]byte)
		a512 = new([512]byte)
		a256 = new([256]byte)
	}
}

// checkAllocations validates that the profile records collected for
// the named function are consistent with count contiguous allocations
// of the specified sizes.
func checkAllocations(records []runtime.MemProfileRecord, fname string, count int64, size []int64) {
	a := allocObjects(records, fname)
	firstLine := 0
	for ln := range a {
		if firstLine == 0 || firstLine > ln {
			firstLine = ln
		}
	}
	var totalcount int64
	for i, w := range size {
		ln := firstLine + i
		s := a[ln]
		checkValue(fname, ln, "objects", count, s.objects)
		checkValue(fname, ln, "bytes", count*w, s.bytes)
		totalcount += s.objects
	}
	// Check the total number of allocations, to ensure some sampling occurred.
	if totalwant := count * int64(len(size)); totalcount <= 0 || totalcount > totalwant*1024 {
		panic(fmt.Sprintf("%s want total count > 0 && <= %d, got %d", fname, totalwant*1024, totalcount))
	}
}

// checkValue checks an unsampled value against a range.
func checkValue(fname string, ln int, name string, want, got int64) {
	if got < 0 || got > 1024*want {
		panic(fmt.Sprintf("%s:%d want %s >= 0 && <= %d, got %d", fname, ln, name, 1024*want, got))
	}
}

func getMemProfileRecords() []runtime.MemProfileRecord {
	// Find out how many records there are (MemProfile(nil, true)),
	// allocate that many records, and get the data.
	// There's a race—more records might be added between
	// the two calls—so allocate a few extra records for safety
	// and also try again if we're very unlucky.
	// The loop should only execute one iteration in the common case.
	var p []runtime.MemProfileRecord
	n, ok := runtime.MemProfile(nil, true)
	for {
		// Allocate room for a slightly bigger profile,
		// in case a few more entries have been added
		// since the call to MemProfile.
		p = make([]runtime.MemProfileRecord, n+50)
		n, ok = runtime.MemProfile(p, true)
		if ok {
			p = p[0:n]
			break
		}
		// Profile grew; try again.
	}
	return p
}

type allocStat struct {
	bytes, objects int64
}

// allocObjects examines the profile records for the named function
// and returns the allocation stats aggregated by source line number.
func allocObjects(records []runtime.MemProfileRecord, function string) map[int]allocStat {
	a := make(map[int]allocStat)
	for _, r := range records {
		for _, s := range r.Stack0 {
			if s == 0 {
				break
			}
			if f := runtime.FuncForPC(s); f != nil {
				name := f.Name()
				_, line := f.FileLine(s)
				if name == function {
					allocStat := a[line]
					allocStat.bytes += r.AllocBytes
					allocStat.objects += r.AllocObjects
					a[line] = allocStat
				}
			}
		}
	}
	for line, stats := range a {
		objects, bytes := scaleHeapSample(stats.objects, stats.bytes, int64(runtime.MemProfileRate))
		a[line] = allocStat{bytes, objects}
	}
	return a
}

// scaleHeapSample unsamples heap allocations.
// Taken from src/cmd/pprof/internal/profile/legacy_profile.go
func scaleHeapSample(count, size, rate int64) (int64, int64) {
	if count == 0 || size == 0 {
		return 0, 0
	}

	if rate <= 1 {
		// if rate==1 all samples were collected so no adjustment is needed.
		// if rate<1 treat as unknown and skip scaling.
		return count, size
	}

	avgSize := float64(size) / float64(count)
	scale := 1 / (1 - math.Exp(-avgSize/float64(rate)))

	return int64(float64(count) * scale), int64(float64(size) * scale)
}
<commit_msg>test: disable flaky heapsampling test for now<commit_after>// run

// Copyright 2009 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.

// Test heap sampling logic.

package main

import (
	"fmt"
	"math"
	"runtime"
)

var a16 *[16]byte
var a512 *[512]byte
var a256 *[256]byte
var a1k *[1024]byte
var a64k *[64 * 1024]byte

// This test checks that heap sampling produces reasonable
// results. Note that heap sampling uses randomization, so the results
// vary for run to run. This test only checks that the resulting
// values appear reasonable.
func main() {
	return // TODO: fix this flaky test; golang.org/issue/13098

	const countInterleaved = 10000
	allocInterleaved(countInterleaved)
	checkAllocations(getMemProfileRecords(), "main.allocInterleaved", countInterleaved, []int64{256 * 1024, 1024, 256 * 1024, 512, 256 * 1024, 256})

	const count = 100000
	alloc(count)
	checkAllocations(getMemProfileRecords(), "main.alloc", count, []int64{1024, 512, 256})
}

// allocInterleaved stress-tests the heap sampling logic by
// interleaving large and small allocations.
func allocInterleaved(n int) {
	for i := 0; i < n; i++ {
		// Test verification depends on these lines being contiguous.
		a64k = new([64 * 1024]byte)
		a1k = new([1024]byte)
		a64k = new([64 * 1024]byte)
		a512 = new([512]byte)
		a64k = new([64 * 1024]byte)
		a256 = new([256]byte)
	}
}

// alloc performs only small allocations for sanity testing.
func alloc(n int) {
	for i := 0; i < n; i++ {
		// Test verification depends on these lines being contiguous.
		a1k = new([1024]byte)
		a512 = new([512]byte)
		a256 = new([256]byte)
	}
}

// checkAllocations validates that the profile records collected for
// the named function are consistent with count contiguous allocations
// of the specified sizes.
func checkAllocations(records []runtime.MemProfileRecord, fname string, count int64, size []int64) {
	a := allocObjects(records, fname)
	firstLine := 0
	for ln := range a {
		if firstLine == 0 || firstLine > ln {
			firstLine = ln
		}
	}
	var totalcount int64
	for i, w := range size {
		ln := firstLine + i
		s := a[ln]
		checkValue(fname, ln, "objects", count, s.objects)
		checkValue(fname, ln, "bytes", count*w, s.bytes)
		totalcount += s.objects
	}
	// Check the total number of allocations, to ensure some sampling occurred.
	if totalwant := count * int64(len(size)); totalcount <= 0 || totalcount > totalwant*1024 {
		panic(fmt.Sprintf("%s want total count > 0 && <= %d, got %d", fname, totalwant*1024, totalcount))
	}
}

// checkValue checks an unsampled value against a range.
func checkValue(fname string, ln int, name string, want, got int64) {
	if got < 0 || got > 1024*want {
		panic(fmt.Sprintf("%s:%d want %s >= 0 && <= %d, got %d", fname, ln, name, 1024*want, got))
	}
}

func getMemProfileRecords() []runtime.MemProfileRecord {
	// Find out how many records there are (MemProfile(nil, true)),
	// allocate that many records, and get the data.
	// There's a race—more records might be added between
	// the two calls—so allocate a few extra records for safety
	// and also try again if we're very unlucky.
	// The loop should only execute one iteration in the common case.
	var p []runtime.MemProfileRecord
	n, ok := runtime.MemProfile(nil, true)
	for {
		// Allocate room for a slightly bigger profile,
		// in case a few more entries have been added
		// since the call to MemProfile.
		p = make([]runtime.MemProfileRecord, n+50)
		n, ok = runtime.MemProfile(p, true)
		if ok {
			p = p[0:n]
			break
		}
		// Profile grew; try again.
	}
	return p
}

type allocStat struct {
	bytes, objects int64
}

// allocObjects examines the profile records for the named function
// and returns the allocation stats aggregated by source line number.
func allocObjects(records []runtime.MemProfileRecord, function string) map[int]allocStat {
	a := make(map[int]allocStat)
	for _, r := range records {
		for _, s := range r.Stack0 {
			if s == 0 {
				break
			}
			if f := runtime.FuncForPC(s); f != nil {
				name := f.Name()
				_, line := f.FileLine(s)
				if name == function {
					allocStat := a[line]
					allocStat.bytes += r.AllocBytes
					allocStat.objects += r.AllocObjects
					a[line] = allocStat
				}
			}
		}
	}
	for line, stats := range a {
		objects, bytes := scaleHeapSample(stats.objects, stats.bytes, int64(runtime.MemProfileRate))
		a[line] = allocStat{bytes, objects}
	}
	return a
}

// scaleHeapSample unsamples heap allocations.
// Taken from src/cmd/pprof/internal/profile/legacy_profile.go
func scaleHeapSample(count, size, rate int64) (int64, int64) {
	if count == 0 || size == 0 {
		return 0, 0
	}

	if rate <= 1 {
		// if rate==1 all samples were collected so no adjustment is needed.
		// if rate<1 treat as unknown and skip scaling.
		return count, size
	}

	avgSize := float64(size) / float64(count)
	scale := 1 / (1 - math.Exp(-avgSize/float64(rate)))

	return int64(float64(count) * scale), int64(float64(size) * scale)
}
<|endoftext|>


<commit_before>package test

import "testing"

func TestReceiveOfflineQueue(t *testing.T) {
	s := NewServerHelper(t).SeedDB()
	defer s.Stop()
	c1 := NewClientHelper(t).DefaultCert().Dial()
	defer c1.Close()

	_ = c1.WriteRequest("msg.send", map[string]string{"to": "2", "msg": "How do you do?"})
	// todo: read ack or automate that?

	c2 := NewClientHelper(t).Cert(client2Cert, client2Key).Dial()
	defer c2.Close()

	// _ = c1.WriteRequest("msg.recv", nil)

	// t.Fatal("Failed to receive queued messages after coming online")
	// t.Fatal("Failed to send ACK for received message queue")
}

func TestReceiveEcho(t *testing.T) {
	// send message to user with ID: "client.127.0.0.1"
}
<commit_msg>expand todo item<commit_after>package test

import "testing"

func TestReceiveOfflineQueue(t *testing.T) {
	s := NewServerHelper(t).SeedDB()
	defer s.Stop()
	c1 := NewClientHelper(t).DefaultCert().Dial()
	defer c1.Close()

	_ = c1.WriteRequest("msg.send", map[string]string{"to": "2", "msg": "How do you do?"})
	// todo: read ack manually or automate ack (just like sender does with channels and promises)

	c2 := NewClientHelper(t).Cert(client2Cert, client2Key).Dial()
	defer c2.Close()

	// _ = c1.WriteRequest("msg.recv", nil)

	// t.Fatal("Failed to receive queued messages after coming online")
	// t.Fatal("Failed to send ACK for received message queue")
}

func TestReceiveEcho(t *testing.T) {
	// send message to user with ID: "client.127.0.0.1"
}
<|endoftext|>