<commit_before>package sudoku

//GridModification is a series of CellModifications to apply to a Grid.
type GridModifcation []*CellModification

//CellModification represents a modification to be made to a given Cell in a
//grid.
type CellModification struct {
	//The cell representing the cell to modify. The cell's analog (at the same
	//row, col address) will be modified in the new grid.
	Cell Cell
	//The number to put in the cell. Negative numbers signify no changes.
	Number int
	//The excludes to proactively set. Invalid numbers will be ignored.
	//Indexes not listed will be left the same.
	ExcludesChanges map[int]bool
	//The marks to proactively set. Invalid numbers will be ignored.
	//Indexes not listed will be left the same.
	MarksChanges map[int]bool
}

//TODO: audit all uses of step/compoundstep.Apply()

//TOOD: make readOnlyCellImpl. Test if neighbors should be derived or not. Can
//burn excludes and impossibles into one array. Everything should be actual
//contiguous memory, no pointers.

//TODO: make readOnlyGridImpl. Two possible approaches: a version that is
//incredibly easy to copy and then do minor tweaks. Or a version that stores a
//dictionary of cell configs, and any time you grab a Cell we look it up in
//the dict or in the ancestors' dicts.

//newCellModification returns a CellModification for the given cell that is a
//no-op.
func newCellModification(cell Cell) *CellModification {
	return &CellModification{
		Cell:            cell,
		Number:          -1,
		ExcludesChanges: make(map[int]bool),
		MarksChanges:    make(map[int]bool),
	}
}

//equivalent returns true if the other grid modification is equivalent to this one.
func (m GridModifcation) equivalent(other GridModifcation) bool {
	if len(m) != len(other) {
		return false
	}
	for i, modification := range m {
		otherModification := other[i]
		if modification.Cell.ref().String() != otherModification.Cell.ref().String() {
			return false
		}
		if modification.Number != otherModification.Number {
			return false
		}

		if len(modification.ExcludesChanges) != len(otherModification.ExcludesChanges) {
			return false
		}

		for key, val := range modification.ExcludesChanges {
			otherVal, ok := otherModification.ExcludesChanges[key]
			if !ok {
				return false
			}
			if val != otherVal {
				return false
			}
		}

		if len(modification.MarksChanges) != len(otherModification.MarksChanges) {
			return false
		}

		for key, val := range modification.MarksChanges {
			otherVal, ok := otherModification.MarksChanges[key]
			if !ok {
				return false
			}
			if val != otherVal {
				return false
			}
		}
	}
	return true
}

func (self *gridImpl) CopyWithModifications(modifications GridModifcation) Grid {
	//TODO: when we have an honest-to-god readonly grid impl, optimize this.
	result := self.MutableCopy()

	for _, modification := range modifications {
		cell := modification.Cell.MutableInGrid(result)

		if modification.Number >= 0 && modification.Number < DIM {
			cell.SetNumber(modification.Number)
		}

		for key, val := range modification.ExcludesChanges {
			//setExcluded will skip invalid entries
			cell.SetExcluded(key, val)
		}

		for key, val := range modification.MarksChanges {
			//SetMark will skip invalid numbers
			cell.SetMark(key, val)
		}
	}

	return result
}
<commit_msg>Added a note on implementation strategy<commit_after>package sudoku

//GridModification is a series of CellModifications to apply to a Grid.
type GridModifcation []*CellModification

//CellModification represents a modification to be made to a given Cell in a
//grid.
type CellModification struct {
	//The cell representing the cell to modify. The cell's analog (at the same
	//row, col address) will be modified in the new grid.
	Cell Cell
	//The number to put in the cell. Negative numbers signify no changes.
	Number int
	//The excludes to proactively set. Invalid numbers will be ignored.
	//Indexes not listed will be left the same.
	ExcludesChanges map[int]bool
	//The marks to proactively set. Invalid numbers will be ignored.
	//Indexes not listed will be left the same.
	MarksChanges map[int]bool
}

//TODO: audit all uses of step/compoundstep.Apply()

//TOOD: make readOnlyCellImpl. Test if neighbors should be derived or not.
//Everything should be actual contiguous memory, no pointers (except for
//grid). Likely should make cellImpl embed a readOnlyCellImpl and only
//override items it needs to.

//TODO: make readOnlyGridImpl. Two possible approaches: a version that is
//incredibly easy to copy and then do minor tweaks. Or a version that stores a
//dictionary of cell configs, and any time you grab a Cell we look it up in
//the dict or in the ancestors' dicts.

//newCellModification returns a CellModification for the given cell that is a
//no-op.
func newCellModification(cell Cell) *CellModification {
	return &CellModification{
		Cell:            cell,
		Number:          -1,
		ExcludesChanges: make(map[int]bool),
		MarksChanges:    make(map[int]bool),
	}
}

//equivalent returns true if the other grid modification is equivalent to this one.
func (m GridModifcation) equivalent(other GridModifcation) bool {
	if len(m) != len(other) {
		return false
	}
	for i, modification := range m {
		otherModification := other[i]
		if modification.Cell.ref().String() != otherModification.Cell.ref().String() {
			return false
		}
		if modification.Number != otherModification.Number {
			return false
		}

		if len(modification.ExcludesChanges) != len(otherModification.ExcludesChanges) {
			return false
		}

		for key, val := range modification.ExcludesChanges {
			otherVal, ok := otherModification.ExcludesChanges[key]
			if !ok {
				return false
			}
			if val != otherVal {
				return false
			}
		}

		if len(modification.MarksChanges) != len(otherModification.MarksChanges) {
			return false
		}

		for key, val := range modification.MarksChanges {
			otherVal, ok := otherModification.MarksChanges[key]
			if !ok {
				return false
			}
			if val != otherVal {
				return false
			}
		}
	}
	return true
}

func (self *gridImpl) CopyWithModifications(modifications GridModifcation) Grid {
	//TODO: when we have an honest-to-god readonly grid impl, optimize this.
	result := self.MutableCopy()

	for _, modification := range modifications {
		cell := modification.Cell.MutableInGrid(result)

		if modification.Number >= 0 && modification.Number < DIM {
			cell.SetNumber(modification.Number)
		}

		for key, val := range modification.ExcludesChanges {
			//setExcluded will skip invalid entries
			cell.SetExcluded(key, val)
		}

		for key, val := range modification.MarksChanges {
			//SetMark will skip invalid numbers
			cell.SetMark(key, val)
		}
	}

	return result
}
<|endoftext|>


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

package main

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

var cmdRun = &Command{
	UsageLine: "run [build flags] gofiles... [arguments...]",
	Short:     "compile and run Go program",
	Long: `
Run compiles and runs the main package comprising the named Go source files.

For more about build flags, see 'go help build'.

See also: go build.
	`,
}

func init() {
	cmdRun.Run = runRun // break init loop

	cmdRun.Flag.BoolVar(&buildA, "a", false, "")
	cmdRun.Flag.BoolVar(&buildN, "n", false, "")
	cmdRun.Flag.BoolVar(&buildX, "x", false, "")
}

func printStderr(args ...interface{}) (int, error) {
	return fmt.Fprint(os.Stderr, args...)
}

func runRun(cmd *Command, args []string) {
	var b builder
	b.init()
	b.print = printStderr
	i := 0
	for i < len(args) && strings.HasSuffix(args[i], ".go") {
		i++
	}
	files, cmdArgs := args[:i], args[i:]
	p := goFilesPackage(files)
	if p.Error != nil {
		fatalf("%s", p.Error)
	}
	if p.Name != "main" {
		fatalf("cannot run non-main package")
	}
	p.target = "" // must build - not up to date
	a1 := b.action(modeBuild, modeBuild, p)
	a := &action{f: (*builder).runProgram, args: cmdArgs, deps: []*action{a1}}
	b.do(a)
}

// runProgram is the action for running a binary that has already
// been compiled.  We ignore exit status.
func (b *builder) runProgram(a *action) error {
	if buildN || buildX {
		b.showcmd("", "%s %s", a.deps[0].target, strings.Join(a.args, " "))
		if buildN {
			return nil
		}
	}

	runStdin(a.deps[0].target, a.args)
	return nil
}

// runStdin is like run, but connects Stdin.
func runStdin(cmdargs ...interface{}) {
	cmdline := stringList(cmdargs...)
	cmd := exec.Command(cmdline[0], cmdline[1:]...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		errorf("%v", err)
	}
}
<commit_msg>cmd/go: honour buildflags in go run<commit_after>// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

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

var cmdRun = &Command{
	UsageLine: "run [build flags] gofiles... [arguments...]",
	Short:     "compile and run Go program",
	Long: `
Run compiles and runs the main package comprising the named Go source files.

For more about build flags, see 'go help build'.

See also: go build.
	`,
}

func init() {
	cmdRun.Run = runRun // break init loop

	addBuildFlags(cmdRun)
}

func printStderr(args ...interface{}) (int, error) {
	return fmt.Fprint(os.Stderr, args...)
}

func runRun(cmd *Command, args []string) {
	var b builder
	b.init()
	b.print = printStderr
	i := 0
	for i < len(args) && strings.HasSuffix(args[i], ".go") {
		i++
	}
	files, cmdArgs := args[:i], args[i:]
	p := goFilesPackage(files)
	if p.Error != nil {
		fatalf("%s", p.Error)
	}
	if p.Name != "main" {
		fatalf("cannot run non-main package")
	}
	p.target = "" // must build - not up to date
	a1 := b.action(modeBuild, modeBuild, p)
	a := &action{f: (*builder).runProgram, args: cmdArgs, deps: []*action{a1}}
	b.do(a)
}

// runProgram is the action for running a binary that has already
// been compiled.  We ignore exit status.
func (b *builder) runProgram(a *action) error {
	if buildN || buildX {
		b.showcmd("", "%s %s", a.deps[0].target, strings.Join(a.args, " "))
		if buildN {
			return nil
		}
	}

	runStdin(a.deps[0].target, a.args)
	return nil
}

// runStdin is like run, but connects Stdin.
func runStdin(cmdargs ...interface{}) {
	cmdline := stringList(cmdargs...)
	cmd := exec.Command(cmdline[0], cmdline[1:]...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		errorf("%v", err)
	}
}
<|endoftext|>


<commit_before>// 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.

// +build ignore

/*

Ld is the portable code for a modified version of the Plan 9 linker.  The original is documented at

	http://plan9.bell-labs.com/magic/man2html/1/8l

It reads object files (.5, .6, or .8 files) and writes a binary named for the
architecture (5.out, 6.out, 8.out) by default (if $GOOS is windows, a .exe suffix
will be appended).

Major changes include:
	- support for ELF, Mach-O and PE binary files
	- support for segmented stacks (this feature is implemented here, not in the compilers).

Original options are listed on the manual page linked above.

Usage:
	go tool 6l [flags] mainObj
Substitute 6l with 8l or 5l as appropriate.

Options new in this version:

	-d
		Elide the dynamic linking header.  With this option, the binary
		is statically linked and does not refer to a dynamic linker.  Without this option
		(the default), the binary's contents are identical but it is loaded with a dynamic
		linker. This flag cannot be used when $GOOS is windows.
	-H darwin     (only in 6l/8l)
		Write Apple Mach-O binaries (default when $GOOS is darwin)
	-H dragonfly  (only in 6l/8l)
		Write DragonFly ELF binaries (default when $GOOS is dragonfly)
	-H linux
		Write Linux ELF binaries (default when $GOOS is linux)
	-H freebsd
		Write FreeBSD ELF binaries (default when $GOOS is freebsd)
	-H netbsd
		Write NetBSD ELF binaries (default when $GOOS is netbsd)
	-H openbsd    (only in 6l/8l)
		Write OpenBSD ELF binaries (default when $GOOS is openbsd)
	-H windows    (only in 6l/8l)
		Write Windows PE32+ Console binaries (default when $GOOS is windows)
	-H windowsgui (only in 6l/8l)
		Write Windows PE32+ GUI binaries
	-I interpreter
		Set the ELF dynamic linker to use.
	-L dir1 -L dir2
		Search for libraries (package files) in dir1, dir2, etc.
		The default is the single location $GOROOT/pkg/$GOOS_$GOARCH.
	-r dir1:dir2:...
		Set the dynamic linker search path when using ELF.
	-s
		Omit the symbol table and debug information.
	-V
		Print the linker version.
	-X symbol value
		Set the value of an otherwise uninitialized string variable.
		The symbol name should be of the form importpath.name,
		as displayed in the symbol table printed by "go tool nm".
	-race
		Link with race detection libraries.
	-B value
		Add a NT_GNU_BUILD_ID note when using ELF.  The value
		should start with 0x and be an even number of hex digits.
	-Z
		Zero stack on function entry. This is expensive but it might
		be useful in cases where you are suffering from false positives
		during garbage collection and are willing to trade the CPU time
		for getting rid of the false positives.
		NOTE: it only eliminates false positives caused by other function
		calls, not false positives caused by dead temporaries stored in
		the current function call.
	-linkmode argument
		Set the linkmode.  The argument must be one of
		internal, external, or auto.  The default is auto.
		This sets the linking mode as described in
		../cgo/doc.go.
	-tmpdir dir
		Set the location to use for any temporary files.  The
		default is a newly created directory that is removed
		after the linker completes.  Temporary files are only
		used in external linking mode.
	-extld name
		Set the name of the external linker to use in external
		linking mode.  The default is "gcc".
	-extldflags flags
		Set space-separated trailing flags to pass to the
		external linker in external linking mode.  The default
		is to not pass any additional trailing flags.
*/
package main
<commit_msg>cmd/ld: document the -w flag, which disables DWARF generation<commit_after>// 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.

// +build ignore

/*

Ld is the portable code for a modified version of the Plan 9 linker.  The original is documented at

	http://plan9.bell-labs.com/magic/man2html/1/8l

It reads object files (.5, .6, or .8 files) and writes a binary named for the
architecture (5.out, 6.out, 8.out) by default (if $GOOS is windows, a .exe suffix
will be appended).

Major changes include:
	- support for ELF, Mach-O and PE binary files
	- support for segmented stacks (this feature is implemented here, not in the compilers).

Original options are listed on the manual page linked above.

Usage:
	go tool 6l [flags] mainObj
Substitute 6l with 8l or 5l as appropriate.

Options new in this version:

	-d
		Elide the dynamic linking header.  With this option, the binary
		is statically linked and does not refer to a dynamic linker.  Without this option
		(the default), the binary's contents are identical but it is loaded with a dynamic
		linker. This flag cannot be used when $GOOS is windows.
	-H darwin     (only in 6l/8l)
		Write Apple Mach-O binaries (default when $GOOS is darwin)
	-H dragonfly  (only in 6l/8l)
		Write DragonFly ELF binaries (default when $GOOS is dragonfly)
	-H linux
		Write Linux ELF binaries (default when $GOOS is linux)
	-H freebsd
		Write FreeBSD ELF binaries (default when $GOOS is freebsd)
	-H netbsd
		Write NetBSD ELF binaries (default when $GOOS is netbsd)
	-H openbsd    (only in 6l/8l)
		Write OpenBSD ELF binaries (default when $GOOS is openbsd)
	-H windows    (only in 6l/8l)
		Write Windows PE32+ Console binaries (default when $GOOS is windows)
	-H windowsgui (only in 6l/8l)
		Write Windows PE32+ GUI binaries
	-I interpreter
		Set the ELF dynamic linker to use.
	-L dir1 -L dir2
		Search for libraries (package files) in dir1, dir2, etc.
		The default is the single location $GOROOT/pkg/$GOOS_$GOARCH.
	-r dir1:dir2:...
		Set the dynamic linker search path when using ELF.
	-s
		Omit the symbol table and debug information.
	-V
		Print the linker version.
	-w
		Omit the DWARF symbol table.
	-X symbol value
		Set the value of an otherwise uninitialized string variable.
		The symbol name should be of the form importpath.name,
		as displayed in the symbol table printed by "go tool nm".
	-race
		Link with race detection libraries.
	-B value
		Add a NT_GNU_BUILD_ID note when using ELF.  The value
		should start with 0x and be an even number of hex digits.
	-Z
		Zero stack on function entry. This is expensive but it might
		be useful in cases where you are suffering from false positives
		during garbage collection and are willing to trade the CPU time
		for getting rid of the false positives.
		NOTE: it only eliminates false positives caused by other function
		calls, not false positives caused by dead temporaries stored in
		the current function call.
	-linkmode argument
		Set the linkmode.  The argument must be one of
		internal, external, or auto.  The default is auto.
		This sets the linking mode as described in
		../cgo/doc.go.
	-tmpdir dir
		Set the location to use for any temporary files.  The
		default is a newly created directory that is removed
		after the linker completes.  Temporary files are only
		used in external linking mode.
	-extld name
		Set the name of the external linker to use in external
		linking mode.  The default is "gcc".
	-extldflags flags
		Set space-separated trailing flags to pass to the
		external linker in external linking mode.  The default
		is to not pass any additional trailing flags.
*/
package main
<|endoftext|>


<commit_before>// Copyright (c) 2013 Ostap Cherkashin, Julius Chrobak. You can use this
// source code under the terms of the MIT License found in the LICENSE file.

package main

import (
	"bufio"
	"encoding/json"
	"encoding/xml"
	"errors"
	"fmt"
	"io"
	"log"
	"math"
	"path"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"time"
)

type Body chan Value

type Store struct {
	types  map[string]Type
	values map[string]Value
}

type Stats struct {
	Total int
	Found int
}

type line struct {
	lineNo  int
	lineStr string
}

var StatsFailed = Stats{-1, -1}

func NewStore() Store {
	return Store{make(map[string]Type), make(map[string]Value)}
}

func (s Store) IsDef(name string) bool {
	return s.types[name] != nil
}

func (s Store) Add(fileName string, r io.Reader) error {
	name := path.Base(fileName)
	if dot := strings.Index(name, "."); dot > 0 {
		name = name[:dot]
	}

	if !IsIdent(name) {
		return fmt.Errorf("invalid file name: '%v' cannot be used as an identifier (ignoring)", name)
	}

	var t Type
	var v Value
	var err error

	if path.Ext(fileName) == ".json" {
		t, v, err = readJSON(r)
	} else if path.Ext(fileName) == ".xml" {
		t, v, err = readXML(r)
	} else {
		t, v, err = readTSV(r, fileName)
	}

	if err != nil {
		return fmt.Errorf("failed to load %v: %v", fileName, err)
	}

	s.types[name] = t
	s.values[name] = v

	switch v.(type) {
	case List:
		log.Printf("stored %v (recs %v)", name, len(v.(List)))
	default:
		log.Printf("stored %v (single object)", name)
	}
	return nil
}

func (s Store) Decls() *Decls {
	decls := NewDecls()
	for k, v := range s.values {
		decls.Declare(k, v, s.types[k])
	}

	decls.AddFunc(FuncTrunc())
	decls.AddFunc(FuncDist())
	decls.AddFunc(FuncTrim())
	decls.AddFunc(FuncLower())
	decls.AddFunc(FuncUpper())
	decls.AddFunc(FuncFuzzy())
	decls.AddFunc(FuncReplace())

	return decls
}

func IsIdent(s string) bool {
	ident, _ := regexp.MatchString("^\\w+$", s)
	return ident
}

func toScalar(s string) interface{} {
	num, err := strconv.ParseFloat(s, 64)
	if err != nil || math.IsNaN(num) || math.IsInf(num, 0) {
		return s
	} else {
		return num
	}
}

func name(prefix string, n xml.Name) string {
	if n.Space == "" {
		return prefix + n.Local
	}

	return prefix + n.Space + ":" + n.Local
}

func alloc() map[string]interface{} {
	res := make(map[string]interface{})
	res["text()"] = ""
	return res
}

func readXML(r io.Reader) (Type, Value, error) {
	dec := xml.NewDecoder(r)

	value := alloc() /* root element */
	stack := append(make([]map[string]interface{}, 0), value)
	names := append(make([]string, 0), "")
	top := 1

	for {
		tok, err := dec.RawToken()
		if err == io.EOF && top == 1 {
			break
		}

		if err != nil {
			return nil, nil, err
		}

		switch t := tok.(type) {
		case xml.StartElement:
			val := alloc()
			n := name("", t.Name)

			for _, v := range t.Attr {
				val[name("@", v.Name)] = toScalar(v.Value)
			}

			parent := stack[top-1]
			if prev, ok := parent[n]; ok {
				switch e := prev.(type) {
				case []interface{}:
					parent[n] = append(e, val)
				default:
					parent[n] = []interface{}{e, val}
				}
			} else {
				parent[n] = val
			}

			if top >= len(stack) {
				stack = append(stack, val)
				names = append(names, n)
			} else {
				stack[top] = val
				names[top] = n
			}
			top++
		case xml.EndElement:
			exp := names[top-1]
			got := name("", t.Name)
			if exp != got {
				return nil, nil, fmt.Errorf("XML syntax error: element <%v> closed by </%v>", exp, got)
			}
			top--
		case xml.CharData:
			parent := stack[top-1]
			parent["text()"] = parent["text()"].(string) + string(t)
		default:
			/* ignoring the following token types
			   xml.Comment
			   xml.ProcInst
			   xml.Directive
			*/
		}
	}

	return traverse(nil, value)
}

func traverse(h Type, v interface{}) (Type, Value, error) {
	switch v.(type) {
	case map[string]interface{}:
		elems := v.(map[string]interface{})
		val := make(Object, len(elems))

		var head ObjectType
		switch h.(type) {
		case ObjectType:
			head = h.(ObjectType)
			if len(head) != len(elems) { /* very strict */
				return nil, nil, errors.New("invalid type")
			}
		case nil:
			head = make(ObjectType, len(elems))
		default:
			return nil, nil, errors.New("invalid type")
		}

		idx := 0
		for name, value := range elems {
			t, v, e := traverse(head.Type(name), value)
			if e != nil {
				return nil, nil, e
			}

			if h == nil {
				head[idx].Name = name
				head[idx].Type = t
			}
			i := head.Pos(name)
			if i < 0 {
				return nil, nil, errors.New("invalid type")
			}
			val[i] = v

			idx++
		}

		return head, val, nil
	case []interface{}:
		elems := v.([]interface{})
		val := make(List, len(elems))

		var head ListType
		switch h.(type) {
		case ListType:
			head = h.(ListType)
		case nil:
			head = ListType{}
		default:
			return nil, nil, errors.New("invalid type")
		}

		for idx, value := range elems {
			t, v, e := traverse(head.Elem, value)
			if e != nil {
				return nil, nil, e
			}

			head.Elem = t
			val[idx] = v
		}

		return head, val, nil
	case bool:
		switch h.(type) {
		case nil, ScalarType:
			return ScalarType(0), Bool(v.(bool)), nil
		default:
			return nil, nil, errors.New("invalid type")
		}
	case float64:
		switch h.(type) {
		case nil, ScalarType:
			return ScalarType(0), Number(v.(float64)), nil
		default:
			return nil, nil, errors.New("invalid type")
		}
	default:
		switch h.(type) {
		case nil, ScalarType:
			return ScalarType(0), String(v.(string)), nil
		default:
			return nil, nil, errors.New("invalid type")
		}
	}
}

func readJSON(r io.Reader) (Type, Value, error) {
	dec := json.NewDecoder(r)

	var data interface{}
	err := dec.Decode(&data) /* reading a single valid JSON value */
	if err != nil {
		return nil, nil, err
	}

	return traverse(nil, data)
}

func readTSV(r io.Reader, fileName string) (Type, Value, error) {
	br := bufio.NewReader(r)
	str, err := br.ReadString('\n')
	if err != nil {
		return nil, nil, err
	}

	fields := strings.Split(str, "\t")
	res := make(ObjectType, len(fields))
	for i, f := range fields {
		res[i].Name = strings.Trim(f, " \r\n")
		res[i].Type = ScalarType(0)
	}

	t := ListType{Elem: res}
	return t, readBody(t, fileName, br), nil
}

func readBody(t ListType, fileName string, r *bufio.Reader) List {
	lines := make(chan line, 1024)
	go func() {
		for lineNo := 0; ; lineNo++ {
			lineStr, _ := r.ReadString('\n')
			if len(lineStr) == 0 {
				break
			}
			lines <- line{lineNo, lineStr}
		}
		close(lines)
	}()

	tuples := make(Body, 1024)
	ctl := make(chan int)

	ot := t.Elem.(ObjectType)
	for i := 0; i < runtime.NumCPU(); i++ {
		go tabDelimParser(i, ot, lines, tuples, ctl)
	}
	go func() {
		for i := 0; i < runtime.NumCPU(); i++ {
			<-ctl
		}
		close(tuples)
	}()

	ticker := time.NewTicker(1 * time.Second)
	list := make(List, 0)

	count := 0
	stop := false
	for !stop {
		select {
		case <-ticker.C:
			log.Printf("loading %v (%d tuples)", fileName, count)
		case t, ok := <-tuples:
			if !ok {
				stop = true
				break
			}

			list = append(list, t)
			count++
		}
	}
	ticker.Stop()

	return list
}

func tabDelimParser(id int, ot ObjectType, in chan line, out Body, ctl chan int) {
	count := 0
	for l := range in {
		fields := strings.Split(l.lineStr[:len(l.lineStr)-1], "\t")
		if len(fields) > len(ot) {
			log.Printf("line %d: truncating object (-%d fields)", l.lineNo, len(fields)-len(ot))
			fields = fields[:len(ot)]
		} else if len(fields) < len(ot) {
			log.Printf("line %d: missing fields, appending blank strings", l.lineNo)
			for len(fields) < len(ot) {
				fields = append(fields, "")
			}
		}

		obj := make(Object, len(ot))
		for i, s := range fields {
			num, err := strconv.ParseFloat(s, 64)
			if err != nil || math.IsNaN(num) || math.IsInf(num, 0) {
				obj[i] = String(s)
			} else {
				obj[i] = Number(num)
				count++
			}
		}

		out <- obj
	}

	log.Printf("parser %d found %d numbers\n", id, count)
	ctl <- 1
}
<commit_msg>RFC CSV support<commit_after>// Copyright (c) 2013 Ostap Cherkashin, Julius Chrobak. You can use this
// source code under the terms of the MIT License found in the LICENSE file.

package main

import (
	"encoding/csv"
	"encoding/json"
	"encoding/xml"
	"errors"
	"fmt"
	"io"
	"log"
	"math"
	"path"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"time"
)

type Body chan Value

type Store struct {
	types  map[string]Type
	values map[string]Value
}

type Stats struct {
	Total int
	Found int
}

type line struct {
	lineNo int
	rec    []string
}

var StatsFailed = Stats{-1, -1}

func NewStore() Store {
	return Store{make(map[string]Type), make(map[string]Value)}
}

func (s Store) IsDef(name string) bool {
	return s.types[name] != nil
}

func (s Store) Add(fileName string, r io.Reader) error {
	name := path.Base(fileName)
	if dot := strings.Index(name, "."); dot > 0 {
		name = name[:dot]
	}

	if !IsIdent(name) {
		return fmt.Errorf("invalid file name: '%v' cannot be used as an identifier (ignoring)", name)
	}

	var t Type
	var v Value
	var err error

	if path.Ext(fileName) == ".json" {
		t, v, err = readJSON(r)
	} else if path.Ext(fileName) == ".xml" {
		t, v, err = readXML(r)
	} else if path.Ext(fileName) == ".csv" {
		t, v, err = readCSV(r, fileName, ',')
	} else {
		t, v, err = readCSV(r, fileName, '\t')
	}

	if err != nil {
		return fmt.Errorf("failed to load %v: %v", fileName, err)
	}

	s.types[name] = t
	s.values[name] = v

	switch v.(type) {
	case List:
		log.Printf("stored %v (recs %v)", name, len(v.(List)))
	default:
		log.Printf("stored %v (single object)", name)
	}
	return nil
}

func (s Store) Decls() *Decls {
	decls := NewDecls()
	for k, v := range s.values {
		decls.Declare(k, v, s.types[k])
	}

	decls.AddFunc(FuncTrunc())
	decls.AddFunc(FuncDist())
	decls.AddFunc(FuncTrim())
	decls.AddFunc(FuncLower())
	decls.AddFunc(FuncUpper())
	decls.AddFunc(FuncFuzzy())
	decls.AddFunc(FuncReplace())

	return decls
}

func IsIdent(s string) bool {
	ident, _ := regexp.MatchString("^\\w+$", s)
	return ident
}

func toScalar(s string) interface{} {
	num, err := strconv.ParseFloat(s, 64)
	if err != nil || math.IsNaN(num) || math.IsInf(num, 0) {
		return s
	} else {
		return num
	}
}

func name(prefix string, n xml.Name) string {
	if n.Space == "" {
		return prefix + n.Local
	}

	return prefix + n.Space + ":" + n.Local
}

func alloc() map[string]interface{} {
	res := make(map[string]interface{})
	res["text()"] = ""
	return res
}

func readXML(r io.Reader) (Type, Value, error) {
	dec := xml.NewDecoder(r)

	value := alloc() /* root element */
	stack := append(make([]map[string]interface{}, 0), value)
	names := append(make([]string, 0), "")
	top := 1

	for {
		tok, err := dec.RawToken()
		if err == io.EOF && top == 1 {
			break
		}

		if err != nil {
			return nil, nil, err
		}

		switch t := tok.(type) {
		case xml.StartElement:
			val := alloc()
			n := name("", t.Name)

			for _, v := range t.Attr {
				val[name("@", v.Name)] = toScalar(v.Value)
			}

			parent := stack[top-1]
			if prev, ok := parent[n]; ok {
				switch e := prev.(type) {
				case []interface{}:
					parent[n] = append(e, val)
				default:
					parent[n] = []interface{}{e, val}
				}
			} else {
				parent[n] = val
			}

			if top >= len(stack) {
				stack = append(stack, val)
				names = append(names, n)
			} else {
				stack[top] = val
				names[top] = n
			}
			top++
		case xml.EndElement:
			exp := names[top-1]
			got := name("", t.Name)
			if exp != got {
				return nil, nil, fmt.Errorf("XML syntax error: element <%v> closed by </%v>", exp, got)
			}
			top--
		case xml.CharData:
			parent := stack[top-1]
			parent["text()"] = parent["text()"].(string) + string(t)
		default:
			/* ignoring the following token types
			   xml.Comment
			   xml.ProcInst
			   xml.Directive
			*/
		}
	}

	return traverse(nil, value)
}

func traverse(h Type, v interface{}) (Type, Value, error) {
	switch v.(type) {
	case map[string]interface{}:
		elems := v.(map[string]interface{})
		val := make(Object, len(elems))

		var head ObjectType
		switch h.(type) {
		case ObjectType:
			head = h.(ObjectType)
			if len(head) != len(elems) { /* very strict */
				return nil, nil, errors.New("invalid type")
			}
		case nil:
			head = make(ObjectType, len(elems))
		default:
			return nil, nil, errors.New("invalid type")
		}

		idx := 0
		for name, value := range elems {
			t, v, e := traverse(head.Type(name), value)
			if e != nil {
				return nil, nil, e
			}

			if h == nil {
				head[idx].Name = name
				head[idx].Type = t
			}
			i := head.Pos(name)
			if i < 0 {
				return nil, nil, errors.New("invalid type")
			}
			val[i] = v

			idx++
		}

		return head, val, nil
	case []interface{}:
		elems := v.([]interface{})
		val := make(List, len(elems))

		var head ListType
		switch h.(type) {
		case ListType:
			head = h.(ListType)
		case nil:
			head = ListType{}
		default:
			return nil, nil, errors.New("invalid type")
		}

		for idx, value := range elems {
			t, v, e := traverse(head.Elem, value)
			if e != nil {
				return nil, nil, e
			}

			head.Elem = t
			val[idx] = v
		}

		return head, val, nil
	case bool:
		switch h.(type) {
		case nil, ScalarType:
			return ScalarType(0), Bool(v.(bool)), nil
		default:
			return nil, nil, errors.New("invalid type")
		}
	case float64:
		switch h.(type) {
		case nil, ScalarType:
			return ScalarType(0), Number(v.(float64)), nil
		default:
			return nil, nil, errors.New("invalid type")
		}
	default:
		switch h.(type) {
		case nil, ScalarType:
			return ScalarType(0), String(v.(string)), nil
		default:
			return nil, nil, errors.New("invalid type")
		}
	}
}

func readJSON(r io.Reader) (Type, Value, error) {
	dec := json.NewDecoder(r)

	var data interface{}
	err := dec.Decode(&data) /* reading a single valid JSON value */
	if err != nil {
		return nil, nil, err
	}

	return traverse(nil, data)
}

func readCSV(in io.Reader, fileName string, delim rune) (Type, Value, error) {
	r := csv.NewReader(in)
	r.Comma = delim
	r.LazyQuotes = true
	r.TrailingComma = true
	r.FieldsPerRecord = -1

	rec, err := r.Read()
	if err != nil {
		return nil, nil, err
	}

	head := make(ObjectType, len(rec))
	for i, f := range rec {
		head[i].Name = strings.Trim(f, " \r\n")
		head[i].Type = ScalarType(0)
	}

	t := ListType{Elem: head}
	return t, readBody(t, fileName, r), nil
}

func readBody(t ListType, fileName string, r *csv.Reader) List {
	lines := make(chan line, 1024)
	go func() {
		for lineNo := 0; ; lineNo++ {
			rec, err := r.Read()
			if err == io.EOF {
				break
			} else if err != nil {
				log.Printf("failed to parse %v, %v", fileName, err)
				break
			}
			lines <- line{lineNo, rec}
		}
		close(lines)
	}()

	tuples := make(Body, 1024)
	ctl := make(chan int)

	ot := t.Elem.(ObjectType)
	for i := 0; i < runtime.NumCPU(); i++ {
		go processLine(i, ot, lines, tuples, ctl)
	}
	go func() {
		for i := 0; i < runtime.NumCPU(); i++ {
			<-ctl
		}
		close(tuples)
	}()

	ticker := time.NewTicker(1 * time.Second)
	list := make(List, 0)

	count := 0
	stop := false
	for !stop {
		select {
		case <-ticker.C:
			log.Printf("loading %v (%d tuples)", fileName, count)
		case t, ok := <-tuples:
			if !ok {
				stop = true
				break
			}

			list = append(list, t)
			count++
		}
	}
	ticker.Stop()

	return list
}

func processLine(id int, ot ObjectType, in chan line, out Body, ctl chan int) {
	count := 0
	for l := range in {
		fields := l.rec
		if len(fields) > len(ot) {
			log.Printf("line %d: truncating object (-%d fields)", l.lineNo, len(fields)-len(ot))
			fields = fields[:len(ot)]
		} else if len(fields) < len(ot) {
			log.Printf("line %d: missing fields, appending blank strings", l.lineNo)
			for len(fields) < len(ot) {
				fields = append(fields, "")
			}
		}

		obj := make(Object, len(ot))
		for i, s := range fields {
			num, err := strconv.ParseFloat(s, 64)
			if err != nil || math.IsNaN(num) || math.IsInf(num, 0) {
				obj[i] = String(s)
			} else {
				obj[i] = Number(num)
				count++
			}
		}

		out <- obj
	}

	log.Printf("parser %d found %d numbers\n", id, count)
	ctl <- 1
}
<|endoftext|>


<commit_before>package handlers

import (
	"encoding/json"
	"fmt"
	"net/http"
	"path"
	"strconv"

	"github.com/golang/glog"
	"github.com/zefer/mothership/mpd"
)

type PlayListEntry struct {
	Pos  int    `json:"pos"`
	Name string `json:"name"`
}

func PlayListHandler(c *mpd.Client) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "GET" {
			playListList(c, w, r)
			return
		} else if r.Method == "POST" {
			playListUpdate(c, w, r)
			return
		} else {
			w.WriteHeader(http.StatusMethodNotAllowed)
			return
		}
	})
}

func playListList(c *mpd.Client, w http.ResponseWriter, r *http.Request) {
	data, err := c.C.PlaylistInfo(-1, -1)
	if err != nil {
		glog.Errorln(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	out := make([]*PlayListEntry, len(data))
	for i, item := range data {
		var name string
		if artist, ok := item["Artist"]; ok {
			// Artist - Title
			name = fmt.Sprintf("%s - %s", artist, item["Title"])
		} else if n, ok := item["Name"]; ok {
			// Playlist name.
			name = n
		} else {
			// Default to file name.
			name = path.Base(item["file"])
		}
		out[i] = &PlayListEntry{
			Pos:  i + 1,
			Name: name,
		}
	}
	b, err := json.Marshal(out)
	w.Header().Add("Content-Type", "application/json")
	fmt.Fprint(w, string(b))
}

func playListUpdate(c *mpd.Client, w http.ResponseWriter, r *http.Request) {
	// Parse the JSON body.
	decoder := json.NewDecoder(r.Body)
	var params map[string]interface{}
	err := decoder.Decode(&params)
	if err != nil {
		glog.Errorln(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	uri := params["uri"].(string)
	typ := params["type"].(string)
	replace := params["replace"].(bool)
	play := params["play"].(bool)
	pos := 0
	if uri == "" {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	// Clear the playlist.
	if replace {
		err := c.C.Clear()
		if err != nil {
			glog.Errorln(err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
	}

	// To play from the start of the new items in the playlist, we need to get the
	// current playlist position.
	if !replace {
		data, err := c.C.Status()
		if err != nil {
			glog.Errorln(err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		pos, err = strconv.Atoi(data["playlistlength"])
		if err != nil {
			glog.Errorln(err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		glog.Infof("pos: %d", pos)
	}

	// Add to the playlist.
	if typ == "playlist" {
		err = c.C.PlaylistLoad(uri, -1, -1)
	} else {
		err = c.C.Add(uri)
	}
	if err != nil {
		glog.Errorln(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	// Play.
	if play {
		err := c.C.Play(pos)
		if err != nil {
			glog.Errorln(err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
	}

	w.WriteHeader(http.StatusOK)
}
<commit_msg>Fetch and render only a chunk of huge playlists<commit_after>package handlers

import (
	"encoding/json"
	"fmt"
	"net/http"
	"path"
	"strconv"

	"github.com/golang/glog"
	"github.com/zefer/mothership/mpd"
)

type PlayListEntry struct {
	Pos  int    `json:"pos"`
	Name string `json:"name"`
}

func PlayListHandler(c *mpd.Client) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "GET" {
			playListList(c, w, r)
			return
		} else if r.Method == "POST" {
			playListUpdate(c, w, r)
			return
		} else {
			w.WriteHeader(http.StatusMethodNotAllowed)
			return
		}
	})
}

// Helper that returns a start/end range to query from the current playlist.
// We want the full playlist unless it is huge, in which case we want a small
// chunk of it.
func playlistRange(c *mpd.Client) ([2]int, error) {
	// Don't fetch or display more than this many playlist entries.
	max := 500
	var rng [2]int

	s, err := c.C.Status()
	if err != nil {
		return rng, err
	}
	if _, ok := s["song"]; !ok {
		// No current song playing, so use the whole (empty) playlist.
		return [2]int{-1, -1}, nil
	}

	pos, err := strconv.Atoi(s["song"])
	if err != nil {
		return rng, err
	}
	length, err := strconv.Atoi(s["playlistlength"])
	if err != nil {
		return rng, err
	}

	if length > max {
		// Fetch this chunk of the current playlist. Adjust the starting position to
		// return n items before the current song, for context.
		rng = [2]int{pos - 1, pos + max}
	} else {
		// Fetch all of the current playlist.
		rng = [2]int{-1, -1}
	}

	return rng, nil
}

func playListList(c *mpd.Client, w http.ResponseWriter, r *http.Request) {
	rng, err := playlistRange(c)
	if err != nil {
		glog.Errorln(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	// Fetch all, or a slice of the current playlist.
	data, err := c.C.PlaylistInfo(rng[0], rng[1])
	if err != nil {
		glog.Errorln(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	out := make([]*PlayListEntry, len(data))
	for i, item := range data {
		var name string
		if artist, ok := item["Artist"]; ok {
			// Artist - Title
			name = fmt.Sprintf("%s - %s", artist, item["Title"])
		} else if n, ok := item["Name"]; ok {
			// Playlist name.
			name = n
		} else {
			// Default to file name.
			name = path.Base(item["file"])
		}
		p, err := strconv.Atoi(item["Pos"])
		if err != nil {
			p = 1
		}
		out[i] = &PlayListEntry{
			Pos:  p + 1,
			Name: name,
		}
	}
	b, err := json.Marshal(out)
	w.Header().Add("Content-Type", "application/json")
	fmt.Fprint(w, string(b))
}

func playListUpdate(c *mpd.Client, w http.ResponseWriter, r *http.Request) {
	// Parse the JSON body.
	decoder := json.NewDecoder(r.Body)
	var params map[string]interface{}
	err := decoder.Decode(&params)
	if err != nil {
		glog.Errorln(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	uri := params["uri"].(string)
	typ := params["type"].(string)
	replace := params["replace"].(bool)
	play := params["play"].(bool)
	pos := 0
	if uri == "" {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	// Clear the playlist.
	if replace {
		err := c.C.Clear()
		if err != nil {
			glog.Errorln(err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
	}

	// To play from the start of the new items in the playlist, we need to get the
	// current playlist position.
	if !replace {
		data, err := c.C.Status()
		if err != nil {
			glog.Errorln(err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		pos, err = strconv.Atoi(data["playlistlength"])
		if err != nil {
			glog.Errorln(err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		glog.Infof("pos: %d", pos)
	}

	// Add to the playlist.
	if typ == "playlist" {
		err = c.C.PlaylistLoad(uri, -1, -1)
	} else {
		err = c.C.Add(uri)
	}
	if err != nil {
		glog.Errorln(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	// Play.
	if play {
		err := c.C.Play(pos)
		if err != nil {
			glog.Errorln(err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
	}

	w.WriteHeader(http.StatusOK)
}
<|endoftext|>


<commit_before>package shell

import (
	"context"
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"reflect"
	"strings"
	"sync"
	"syscall"

	"github.com/zetamatta/go-findfile"

	"github.com/zetamatta/nyagos/dos"
	. "github.com/zetamatta/nyagos/ifdbg"
)

var WildCardExpansionAlways = false

type CommandNotFound struct {
	Name string
	Err  error
}

// from "TDM-GCC-64/x86_64-w64-mingw32/include/winbase.h"
const (
	CREATE_NEW_CONSOLE       = 0x10
	CREATE_NEW_PROCESS_GROUP = 0x200
)

func (this CommandNotFound) Stringer() string {
	return fmt.Sprintf("'%s' is not recognized as an internal or external command,\noperable program or batch file", this.Name)
}

func (this CommandNotFound) Error() string {
	return this.Stringer()
}

func isElevationRequired(err error) bool {
	e, ok := err.(*os.PathError)
	return ok && e.Err == syscall.Errno(0x2e4)
}

type Session struct {
	Unreadline []string
}

type Cmd struct {
	*Session
	Stdout       *os.File
	Stderr       *os.File
	Stdin        *os.File
	Args         []string
	HookCount    int
	Tag          interface{}
	PipeSeq      [2]uint
	IsBackGround bool
	RawArgs      []string

	OnFork  func(*Cmd) error
	OffFork func(*Cmd) error
	Closers []io.Closer
}

func (this *Cmd) GetRawArgs() []string {
	return this.RawArgs
}

func (this *Cmd) Close() {
	if this.Closers != nil {
		for _, c := range this.Closers {
			c.Close()
		}
		this.Closers = nil
	}
}

func New() *Cmd {
	this := Cmd{
		Stdin:  os.Stdin,
		Stdout: os.Stdout,
		Stderr: os.Stderr,
	}
	this.PipeSeq[0] = pipeSeq
	this.PipeSeq[1] = 0
	this.Session = &Session{}
	return &this
}

func (this *Cmd) Clone() (*Cmd, error) {
	rv := new(Cmd)
	rv.Args = this.Args
	rv.RawArgs = this.RawArgs
	rv.Stdin = this.Stdin
	rv.Stdout = this.Stdout
	rv.Stderr = this.Stderr
	rv.HookCount = this.HookCount
	rv.Tag = this.Tag
	rv.PipeSeq = this.PipeSeq
	rv.Closers = nil
	rv.OnFork = this.OnFork
	rv.OffFork = this.OffFork
	if this.Session != nil {
		rv.Session = this.Session
	} else {
		rv.Session = &Session{}
	}
	return rv, nil
}

type ArgsHookT func(it *Cmd, args []string) ([]string, error)

var argsHook = func(it *Cmd, args []string) ([]string, error) {
	return args, nil
}

func SetArgsHook(argsHook_ ArgsHookT) (rv ArgsHookT) {
	rv, argsHook = argsHook, argsHook_
	return
}

type HookT func(context.Context, *Cmd) (int, bool, error)

var hook = func(context.Context, *Cmd) (int, bool, error) {
	return 0, false, nil
}

func SetHook(hook_ HookT) (rv HookT) {
	rv, hook = hook, hook_
	return
}

var OnCommandNotFound = func(this *Cmd, err error) error {
	err = &CommandNotFound{this.Args[0], err}
	return err
}

var LastErrorLevel int

func nvl(a *os.File, b *os.File) *os.File {
	if a != nil {
		return a
	} else {
		return b
	}
}

func makeCmdline(args, rawargs []string) string {
	buffer := make([]byte, 0, 1024)
	for i, s := range args {
		if i > 0 {
			buffer = append(buffer, ' ')
		}
		if (len(rawargs) > i && len(rawargs[i]) > 0 && rawargs[i][0] == '"') || strings.ContainsAny(s, " &|<>\t\"") {
			buffer = append(buffer, '"')
			qs := strings.Replace(s, `"`, `\"`, -1)
			buffer = append(buffer, qs...)
			buffer = append(buffer, '"')
		} else {
			buffer = append(buffer, s...)
		}
	}
	return string(buffer)
}

func (this *Cmd) spawnvp_noerrmsg(ctx context.Context) (int, error) {
	// command is empty.
	if len(this.Args) <= 0 {
		return 0, nil
	}
	if DBG {
		print("spawnvp_noerrmsg('", this.Args[0], "')\n")
	}

	// aliases and lua-commands
	if errorlevel, done, err := hook(ctx, this); done || err != nil {
		return errorlevel, err
	}

	// command not found hook
	var err error
	path1 := dos.LookPath(this.Args[0], "NYAGOSPATH")
	if path1 == "" {
		return 255, OnCommandNotFound(this, os.ErrNotExist)
	}
	this.Args[0] = path1

	if DBG {
		print("exec.LookPath(", this.Args[0], ")==", path1, "\n")
	}

	if WildCardExpansionAlways {
		this.Args = findfile.Globs(this.Args)
	}

	cmd1 := exec.Command(this.Args[0], this.Args[1:]...)
	cmd1.Stdin = this.Stdin
	cmd1.Stdout = this.Stdout
	cmd1.Stderr = this.Stderr

	if cmd1.SysProcAttr == nil {
		cmd1.SysProcAttr = new(syscall.SysProcAttr)
	}
	cmdline := makeCmdline(cmd1.Args, this.RawArgs)
	if DBG {
		println(cmdline)
	}
	cmd1.SysProcAttr.CmdLine = cmdline
	err = cmd1.Run()
	if isElevationRequired(err) {
		cmdline := ""
		if len(cmd1.Args) >= 2 {
			cmdline = makeCmdline(cmd1.Args[1:], this.RawArgs[1:])
		}
		if DBG {
			println("ShellExecute:Path=" + cmd1.Args[0])
			println("Args=" + cmdline)
		}
		err = dos.ShellExecute("open", dos.TruePath(cmd1.Args[0]), cmdline, "")
	}
	errorlevel, errorlevelOk := dos.GetErrorLevel(cmd1)
	if errorlevelOk {
		return errorlevel, err
	} else {
		return 255, err
	}
}

type AlreadyReportedError struct {
	Err error
}

func (this AlreadyReportedError) Error() string {
	return ""
}

func IsAlreadyReported(err error) bool {
	_, ok := err.(AlreadyReportedError)
	return ok
}

func (this *Cmd) Spawnvp() (int, error) {
	return this.SpawnvpContext(context.Background())
}

func (this *Cmd) SpawnvpContext(ctx context.Context) (int, error) {
	errorlevel, err := this.spawnvp_noerrmsg(ctx)
	if err != nil && err != io.EOF && !IsAlreadyReported(err) {
		if DBG {
			val := reflect.ValueOf(err)
			fmt.Fprintf(this.Stderr, "error-type=%s\n", val.Type())
		}
		fmt.Fprintln(this.Stderr, err.Error())
		err = AlreadyReportedError{err}
	}
	return errorlevel, err
}

var pipeSeq uint = 0

func (this *Cmd) Interpret(text string) (int, error) {
	return this.InterpretContext(context.Background(), text)
}

type gotoEol struct{}

var GotoEol = gotoEol{}

func (this *Cmd) InterpretContext(ctx_ context.Context, text string) (errorlevel int, finalerr error) {
	if DBG {
		print("Interpret('", text, "')\n")
	}
	if this == nil {
		return 255, errors.New("Fatal Error: Interpret: instance is nil")
	}
	errorlevel = 0
	finalerr = nil

	statements, statementsErr := Parse(text)
	if statementsErr != nil {
		if DBG {
			print("Parse Error:", statementsErr.Error(), "\n")
		}
		return 0, statementsErr
	}
	if argsHook != nil {
		if DBG {
			print("call argsHook\n")
		}
		for _, pipeline := range statements {
			for _, state := range pipeline {
				var err error
				state.Args, err = argsHook(this, state.Args)
				if err != nil {
					return 255, err
				}
			}
		}
		if DBG {
			print("done argsHook\n")
		}
	}
	for _, pipeline := range statements {
		for i, state := range pipeline {
			if state.Term == "|" && (i+1 >= len(pipeline) || len(pipeline[i+1].Args) <= 0) {
				return 255, errors.New("The syntax of the command is incorrect.")
			}
		}
	}

	for _, pipeline := range statements {

		var pipeIn *os.File = nil
		pipeSeq++
		isBackGround := this.IsBackGround
		for _, state := range pipeline {
			if state.Term == "&" {
				isBackGround = true
				break
			}
		}
		var wg sync.WaitGroup
		shutdown_immediately := false
		for i, state := range pipeline {
			if DBG {
				print(i, ": pipeline loop(", state.Args[0], ")\n")
			}
			cmd, err := this.Clone()
			if err != nil {
				return 255, err
			}
			cmd.PipeSeq[0] = pipeSeq
			cmd.PipeSeq[1] = uint(1 + i)
			cmd.IsBackGround = isBackGround

			ctx := context.WithValue(ctx_, GotoEol, func() {
				shutdown_immediately = true
				gotoeol, ok := ctx_.Value(GotoEol).(func())
				if ok {
					gotoeol()
				}
			})

			if pipeIn != nil {
				cmd.Stdin = pipeIn
				cmd.Closers = append(cmd.Closers, pipeIn)
				pipeIn = nil
			}

			if state.Term[0] == '|' {
				var pipeOut *os.File
				pipeIn, pipeOut, err = os.Pipe()
				cmd.Stdout = pipeOut
				if state.Term == "|&" {
					cmd.Stderr = pipeOut
				}
				cmd.Closers = append(cmd.Closers, pipeOut)
			}

			for _, red := range state.Redirect {
				var fd *os.File
				fd, err = red.OpenOn(cmd)
				if err != nil {
					return 0, err
				}
				defer fd.Close()
			}

			cmd.Args = state.Args
			cmd.RawArgs = state.RawArgs
			if i > 0 {
				cmd.IsBackGround = true
			}
			if i == len(pipeline)-1 && state.Term != "&" {
				// foreground execution.
				errorlevel, finalerr = cmd.SpawnvpContext(ctx)
				LastErrorLevel = errorlevel
				cmd.Close()
			} else {
				// background
				if !isBackGround {
					wg.Add(1)
				}
				if cmd.OnFork != nil {
					if err := cmd.OnFork(cmd); err != nil {
						fmt.Fprintln(cmd.Stderr, err.Error())
						return -1, err
					}
				}
				go func(cmd1 *Cmd) {
					if !isBackGround {
						defer wg.Done()
					}
					cmd1.SpawnvpContext(ctx)
					if cmd1.OffFork != nil {
						if err := cmd1.OffFork(cmd1); err != nil {
							fmt.Fprintln(cmd1.Stderr, err.Error())
							goto exit
						}
					}
				exit:
					cmd1.Close()
				}(cmd)
			}
		}
		if !isBackGround {
			wg.Wait()
			if shutdown_immediately {
				return errorlevel, nil
			}
			if len(pipeline) > 0 {
				switch pipeline[len(pipeline)-1].Term {
				case "&&":
					if errorlevel != 0 {
						return errorlevel, nil
					}
				case "||":
					if errorlevel == 0 {
						return errorlevel, nil
					}
				}
			}
		}
	}
	return
}
<commit_msg>Remove unused code for `if`<commit_after>package shell

import (
	"context"
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"reflect"
	"strings"
	"sync"
	"syscall"

	"github.com/zetamatta/go-findfile"

	"github.com/zetamatta/nyagos/dos"
	. "github.com/zetamatta/nyagos/ifdbg"
)

var WildCardExpansionAlways = false

type CommandNotFound struct {
	Name string
	Err  error
}

// from "TDM-GCC-64/x86_64-w64-mingw32/include/winbase.h"
const (
	CREATE_NEW_CONSOLE       = 0x10
	CREATE_NEW_PROCESS_GROUP = 0x200
)

func (this CommandNotFound) Stringer() string {
	return fmt.Sprintf("'%s' is not recognized as an internal or external command,\noperable program or batch file", this.Name)
}

func (this CommandNotFound) Error() string {
	return this.Stringer()
}

func isElevationRequired(err error) bool {
	e, ok := err.(*os.PathError)
	return ok && e.Err == syscall.Errno(0x2e4)
}

type Session struct {
	Unreadline []string
}

type Cmd struct {
	*Session
	Stdout       *os.File
	Stderr       *os.File
	Stdin        *os.File
	Args         []string
	HookCount    int
	Tag          interface{}
	PipeSeq      [2]uint
	IsBackGround bool
	RawArgs      []string

	OnFork  func(*Cmd) error
	OffFork func(*Cmd) error
	Closers []io.Closer
}

func (this *Cmd) GetRawArgs() []string {
	return this.RawArgs
}

func (this *Cmd) Close() {
	if this.Closers != nil {
		for _, c := range this.Closers {
			c.Close()
		}
		this.Closers = nil
	}
}

func New() *Cmd {
	this := Cmd{
		Stdin:  os.Stdin,
		Stdout: os.Stdout,
		Stderr: os.Stderr,
	}
	this.PipeSeq[0] = pipeSeq
	this.PipeSeq[1] = 0
	this.Session = &Session{}
	return &this
}

func (this *Cmd) Clone() (*Cmd, error) {
	rv := new(Cmd)
	rv.Args = this.Args
	rv.RawArgs = this.RawArgs
	rv.Stdin = this.Stdin
	rv.Stdout = this.Stdout
	rv.Stderr = this.Stderr
	rv.HookCount = this.HookCount
	rv.Tag = this.Tag
	rv.PipeSeq = this.PipeSeq
	rv.Closers = nil
	rv.OnFork = this.OnFork
	rv.OffFork = this.OffFork
	if this.Session != nil {
		rv.Session = this.Session
	} else {
		rv.Session = &Session{}
	}
	return rv, nil
}

type ArgsHookT func(it *Cmd, args []string) ([]string, error)

var argsHook = func(it *Cmd, args []string) ([]string, error) {
	return args, nil
}

func SetArgsHook(argsHook_ ArgsHookT) (rv ArgsHookT) {
	rv, argsHook = argsHook, argsHook_
	return
}

type HookT func(context.Context, *Cmd) (int, bool, error)

var hook = func(context.Context, *Cmd) (int, bool, error) {
	return 0, false, nil
}

func SetHook(hook_ HookT) (rv HookT) {
	rv, hook = hook, hook_
	return
}

var OnCommandNotFound = func(this *Cmd, err error) error {
	err = &CommandNotFound{this.Args[0], err}
	return err
}

var LastErrorLevel int

func nvl(a *os.File, b *os.File) *os.File {
	if a != nil {
		return a
	} else {
		return b
	}
}

func makeCmdline(args, rawargs []string) string {
	buffer := make([]byte, 0, 1024)
	for i, s := range args {
		if i > 0 {
			buffer = append(buffer, ' ')
		}
		if (len(rawargs) > i && len(rawargs[i]) > 0 && rawargs[i][0] == '"') || strings.ContainsAny(s, " &|<>\t\"") {
			buffer = append(buffer, '"')
			qs := strings.Replace(s, `"`, `\"`, -1)
			buffer = append(buffer, qs...)
			buffer = append(buffer, '"')
		} else {
			buffer = append(buffer, s...)
		}
	}
	return string(buffer)
}

func (this *Cmd) spawnvp_noerrmsg(ctx context.Context) (int, error) {
	// command is empty.
	if len(this.Args) <= 0 {
		return 0, nil
	}
	if DBG {
		print("spawnvp_noerrmsg('", this.Args[0], "')\n")
	}

	// aliases and lua-commands
	if errorlevel, done, err := hook(ctx, this); done || err != nil {
		return errorlevel, err
	}

	// command not found hook
	var err error
	path1 := dos.LookPath(this.Args[0], "NYAGOSPATH")
	if path1 == "" {
		return 255, OnCommandNotFound(this, os.ErrNotExist)
	}
	this.Args[0] = path1

	if DBG {
		print("exec.LookPath(", this.Args[0], ")==", path1, "\n")
	}

	if WildCardExpansionAlways {
		this.Args = findfile.Globs(this.Args)
	}

	cmd1 := exec.Command(this.Args[0], this.Args[1:]...)
	cmd1.Stdin = this.Stdin
	cmd1.Stdout = this.Stdout
	cmd1.Stderr = this.Stderr

	if cmd1.SysProcAttr == nil {
		cmd1.SysProcAttr = new(syscall.SysProcAttr)
	}
	cmdline := makeCmdline(cmd1.Args, this.RawArgs)
	if DBG {
		println(cmdline)
	}
	cmd1.SysProcAttr.CmdLine = cmdline
	err = cmd1.Run()
	if isElevationRequired(err) {
		cmdline := ""
		if len(cmd1.Args) >= 2 {
			cmdline = makeCmdline(cmd1.Args[1:], this.RawArgs[1:])
		}
		if DBG {
			println("ShellExecute:Path=" + cmd1.Args[0])
			println("Args=" + cmdline)
		}
		err = dos.ShellExecute("open", dos.TruePath(cmd1.Args[0]), cmdline, "")
	}
	errorlevel, errorlevelOk := dos.GetErrorLevel(cmd1)
	if errorlevelOk {
		return errorlevel, err
	} else {
		return 255, err
	}
}

type AlreadyReportedError struct {
	Err error
}

func (this AlreadyReportedError) Error() string {
	return ""
}

func IsAlreadyReported(err error) bool {
	_, ok := err.(AlreadyReportedError)
	return ok
}

func (this *Cmd) Spawnvp() (int, error) {
	return this.SpawnvpContext(context.Background())
}

func (this *Cmd) SpawnvpContext(ctx context.Context) (int, error) {
	errorlevel, err := this.spawnvp_noerrmsg(ctx)
	if err != nil && err != io.EOF && !IsAlreadyReported(err) {
		if DBG {
			val := reflect.ValueOf(err)
			fmt.Fprintf(this.Stderr, "error-type=%s\n", val.Type())
		}
		fmt.Fprintln(this.Stderr, err.Error())
		err = AlreadyReportedError{err}
	}
	return errorlevel, err
}

var pipeSeq uint = 0

func (this *Cmd) Interpret(text string) (int, error) {
	return this.InterpretContext(context.Background(), text)
}

func (this *Cmd) InterpretContext(ctx context.Context, text string) (errorlevel int, finalerr error) {
	if DBG {
		print("Interpret('", text, "')\n")
	}
	if this == nil {
		return 255, errors.New("Fatal Error: Interpret: instance is nil")
	}
	errorlevel = 0
	finalerr = nil

	statements, statementsErr := Parse(text)
	if statementsErr != nil {
		if DBG {
			print("Parse Error:", statementsErr.Error(), "\n")
		}
		return 0, statementsErr
	}
	if argsHook != nil {
		if DBG {
			print("call argsHook\n")
		}
		for _, pipeline := range statements {
			for _, state := range pipeline {
				var err error
				state.Args, err = argsHook(this, state.Args)
				if err != nil {
					return 255, err
				}
			}
		}
		if DBG {
			print("done argsHook\n")
		}
	}
	for _, pipeline := range statements {
		for i, state := range pipeline {
			if state.Term == "|" && (i+1 >= len(pipeline) || len(pipeline[i+1].Args) <= 0) {
				return 255, errors.New("The syntax of the command is incorrect.")
			}
		}
	}

	for _, pipeline := range statements {

		var pipeIn *os.File = nil
		pipeSeq++
		isBackGround := this.IsBackGround
		for _, state := range pipeline {
			if state.Term == "&" {
				isBackGround = true
				break
			}
		}
		var wg sync.WaitGroup
		shutdown_immediately := false
		for i, state := range pipeline {
			if DBG {
				print(i, ": pipeline loop(", state.Args[0], ")\n")
			}
			cmd, err := this.Clone()
			if err != nil {
				return 255, err
			}
			cmd.PipeSeq[0] = pipeSeq
			cmd.PipeSeq[1] = uint(1 + i)
			cmd.IsBackGround = isBackGround

			if pipeIn != nil {
				cmd.Stdin = pipeIn
				cmd.Closers = append(cmd.Closers, pipeIn)
				pipeIn = nil
			}

			if state.Term[0] == '|' {
				var pipeOut *os.File
				pipeIn, pipeOut, err = os.Pipe()
				cmd.Stdout = pipeOut
				if state.Term == "|&" {
					cmd.Stderr = pipeOut
				}
				cmd.Closers = append(cmd.Closers, pipeOut)
			}

			for _, red := range state.Redirect {
				var fd *os.File
				fd, err = red.OpenOn(cmd)
				if err != nil {
					return 0, err
				}
				defer fd.Close()
			}

			cmd.Args = state.Args
			cmd.RawArgs = state.RawArgs
			if i > 0 {
				cmd.IsBackGround = true
			}
			if i == len(pipeline)-1 && state.Term != "&" {
				// foreground execution.
				errorlevel, finalerr = cmd.SpawnvpContext(ctx)
				LastErrorLevel = errorlevel
				cmd.Close()
			} else {
				// background
				if !isBackGround {
					wg.Add(1)
				}
				if cmd.OnFork != nil {
					if err := cmd.OnFork(cmd); err != nil {
						fmt.Fprintln(cmd.Stderr, err.Error())
						return -1, err
					}
				}
				go func(cmd1 *Cmd) {
					if !isBackGround {
						defer wg.Done()
					}
					cmd1.SpawnvpContext(ctx)
					if cmd1.OffFork != nil {
						if err := cmd1.OffFork(cmd1); err != nil {
							fmt.Fprintln(cmd1.Stderr, err.Error())
							goto exit
						}
					}
				exit:
					cmd1.Close()
				}(cmd)
			}
		}
		if !isBackGround {
			wg.Wait()
			if shutdown_immediately {
				return errorlevel, nil
			}
			if len(pipeline) > 0 {
				switch pipeline[len(pipeline)-1].Term {
				case "&&":
					if errorlevel != 0 {
						return errorlevel, nil
					}
				case "||":
					if errorlevel == 0 {
						return errorlevel, nil
					}
				}
			}
		}
	}
	return
}
<|endoftext|>


<commit_before>package tingo

import (
	"fmt"
	"html"
	"strings"
)

type Element struct {
	tagName    string
	parent     *Element
	attributes map[string]string
	isHidden   bool
	isVoid     bool
	isSafe     bool

	children    []*Element
	textPrepend string
	textAppend  string
}

func newVoidElement(tagName string) *Element {
	element := &Element{
		tagName:    tagName,
		attributes: make(map[string]string),
		isVoid:     true,
	}
	return element
}

func newElement(tagName string, children []*Element) *Element {
	element := &Element{
		tagName:    tagName,
		attributes: make(map[string]string),
		children:   children,
	}
	for _, child := range children {
		child.parent = element
	}
	return element
}

// Element methods
// Available for all elements

func (el *Element) Accesskey(key string) *Element {
	el.attributes["accesskey"] = key
	return el
}

func (el *Element) Class(cls string) *Element {
	el.attributes["class"] = cls
	return el
}

func (el *Element) Contenteditable(b bool) *Element {
	if b {
		el.attributes["contenteditable"] = "true"
	} else {
		el.attributes["contenteditable"] = "false"
	}
	return el
}

func (el *Element) Contextmenu(id string) *Element {
	el.attributes["contextmenu"] = id
	return el
}

func (el *Element) Dir(state string) *Element {
	if state == "ltr" || state == "trl" || state == "auto" {
		el.attributes["dir"] = state
	}
	return el
}

func (el *Element) Draggable(b bool) *Element {
	if b {
		el.attributes["draggable"] = "true"
	} else {
		el.attributes["draggable"] = "false"
	}
	return el
}

func (el *Element) Dropzone(state string) *Element {
	if state == "copy" || state == "move" || state == "link" {
		el.attributes["dropzone"] = state
	}
	return el
}

func (el *Element) Hidden(b bool) *Element {
	if b {
		el.attributes["draggable"] = "true"
	} else {
		el.attributes["draggable"] = "false"
	}
	return el
}

func (el *Element) Id(id string) *Element {
	el.attributes["id"] = id
	return el
}

func (el *Element) Lang(lang string) *Element {
	el.attributes["lang"] = lang
	return el
}

func (el *Element) Spellcheck(b bool) *Element {
	if b {
		el.attributes["spellcheck"] = "true"
	} else {
		el.attributes["spellcheck"] = "false"
	}
	return el
}

func (el *Element) Style(style string) *Element {
	el.attributes["style"] = style
	return el
}

func (el *Element) Tabindex(index int) *Element {
	el.attributes["tabindex"] = fmt.Sprintf("%v", index)
	return el
}

func (el *Element) Title(title string) *Element {
	el.attributes["title"] = title
	return el
}

func (el *Element) Translate(b bool) *Element {
	if b {
		el.attributes["translate"] = "yes"
	} else {
		el.attributes["translate"] = "no"
	}
	return el
}

// Restricted

func (el *Element) Type(t string) *Element {
	el.attributes["type"] = t
	return el
}

// Logic and additional methods

func (el *Element) Safe(b bool) *Element {
	// All text and attributes will be escaped by default. Call Safe(true) if you trust the input.
	el.isSafe = b
	return el
}

func (el *Element) If(b bool) *Element {
	// If b is false, this element won't be rendered.
	el.isHidden = !b
	return el
}

func (el *Element) TextPrepend(text string) *Element {
	// Adds text before this element's children. Has no effect on void elements like
.
	el.textPrepend = text
	return el
}

func (el *Element) TextAppend(text string) *Element {
	// Adds text after this element's children. Has no effect on void elements like
.
	el.textAppend = text
	return el
}

func (el *Element) Render() string {
	if el.isHidden {
		return ""
	}

	attributes := make([]string, 0)
	for key, val := range el.attributes {
		attributes = append(attributes, fmt.Sprintf(` %v="%v"`, key, val))
	}

	if el.isVoid {
		// Format
		return fmt.Sprintf(
			`<%v%v>`,
			el.tagName,
			strings.Join(attributes, ""),
		)
	} else {
		children := make([]string, 0)
		for _, child := range el.children {
			children = append(children, child.Render())
		}

		return fmt.Sprintf(
			`<%v%v>%v%v%v</%v>`,
			el.tagName,
			strings.Join(attributes, ""),
			el.textPrepend,
			strings.Join(children, ""),
			el.textAppend,
			el.tagName,
		)
	}
}

func (el *Element) RenderIndent(indent string) string {
	if el.isHidden {
		return ""
	}

	attributes := make([]string, 0)
	for key, val := range el.attributes {
		attributes = append(attributes, fmt.Sprintf(` %v="%v"`, key, val))
	}

	// Calculate depth to find indention level
	depth := 0
	parent := el.parent
	for parent != nil {
		parent = parent.parent
		depth++
	}
	nextIndent := strings.Repeat(indent, depth)

	if el.isVoid {
		// Format
		return fmt.Sprintf(
			"%v<%v%v>",
			nextIndent,
			el.tagName,
			strings.Join(attributes, ""),
		)
	} else {
		children := make([]string, 0)
		for _, child := range el.children {
			children = append(children, child.RenderIndent(indent))
		}

		textPrepend := el.textPrepend
		textAppend := el.textAppend

		if !el.isSafe {
			textPrepend = html.EscapeString(textPrepend)
			textAppend = html.EscapeString(textAppend)
		}

		// If element has children, indent text and children.
		// Otherwise, add appended/prepended text on the same line like text.
		if len(children) > 0 {
			// Make sure prepended / appended text is also indented
			if len(textPrepend) > 0 {
				textPrepend = fmt.Sprintf("%v%v%v\n", indent, nextIndent, textPrepend)
			}
			if len(textAppend) > 0 {
				textAppend = fmt.Sprintf("\n%v%v%v\n", indent, nextIndent, textAppend)
			}
			return fmt.Sprintf(
				"%v<%v%v>\n%v%v%v\n%v</%v>",
				nextIndent,
				el.tagName,
				strings.Join(attributes, ""),
				textPrepend,
				strings.Join(children, "\n"),
				textAppend,
				nextIndent,
				el.tagName,
			)
		} else {
			return fmt.Sprintf(
				"%v<%v%v>%v%v</%v>",
				nextIndent,
				el.tagName,
				strings.Join(attributes, ""),
				textPrepend,
				textAppend,
				el.tagName,
			)
		}
	}
}
<commit_msg>Make elements inherit "safe" mode.<commit_after>package tingo

import (
	"fmt"
	"html"
	"strings"
)

type Element struct {
	tagName    string
	parent     *Element
	attributes map[string]string
	isHidden   bool
	isVoid     bool
	isSafe     bool

	children    []*Element
	textPrepend string
	textAppend  string
}

func newVoidElement(tagName string) *Element {
	element := &Element{
		tagName:    tagName,
		attributes: make(map[string]string),
		isVoid:     true,
	}
	return element
}

func newElement(tagName string, children []*Element) *Element {
	element := &Element{
		tagName:    tagName,
		attributes: make(map[string]string),
		children:   children,
	}
	for _, child := range children {
		child.parent = element
	}
	return element
}

// Element methods
// Available for all elements

func (el *Element) Accesskey(key string) *Element {
	el.attributes["accesskey"] = key
	return el
}

func (el *Element) Class(cls string) *Element {
	el.attributes["class"] = cls
	return el
}

func (el *Element) Contenteditable(b bool) *Element {
	if b {
		el.attributes["contenteditable"] = "true"
	} else {
		el.attributes["contenteditable"] = "false"
	}
	return el
}

func (el *Element) Contextmenu(id string) *Element {
	el.attributes["contextmenu"] = id
	return el
}

func (el *Element) Dir(state string) *Element {
	if state == "ltr" || state == "trl" || state == "auto" {
		el.attributes["dir"] = state
	}
	return el
}

func (el *Element) Draggable(b bool) *Element {
	if b {
		el.attributes["draggable"] = "true"
	} else {
		el.attributes["draggable"] = "false"
	}
	return el
}

func (el *Element) Dropzone(state string) *Element {
	if state == "copy" || state == "move" || state == "link" {
		el.attributes["dropzone"] = state
	}
	return el
}

func (el *Element) Hidden(b bool) *Element {
	if b {
		el.attributes["draggable"] = "true"
	} else {
		el.attributes["draggable"] = "false"
	}
	return el
}

func (el *Element) Id(id string) *Element {
	el.attributes["id"] = id
	return el
}

func (el *Element) Lang(lang string) *Element {
	el.attributes["lang"] = lang
	return el
}

func (el *Element) Spellcheck(b bool) *Element {
	if b {
		el.attributes["spellcheck"] = "true"
	} else {
		el.attributes["spellcheck"] = "false"
	}
	return el
}

func (el *Element) Style(style string) *Element {
	el.attributes["style"] = style
	return el
}

func (el *Element) Tabindex(index int) *Element {
	el.attributes["tabindex"] = fmt.Sprintf("%v", index)
	return el
}

func (el *Element) Title(title string) *Element {
	el.attributes["title"] = title
	return el
}

func (el *Element) Translate(b bool) *Element {
	if b {
		el.attributes["translate"] = "yes"
	} else {
		el.attributes["translate"] = "no"
	}
	return el
}

// Restricted

func (el *Element) Type(t string) *Element {
	el.attributes["type"] = t
	return el
}

// Logic and additional methods

func (el *Element) Safe(b bool) *Element {
	// All text and attributes will be escaped by default. Call Safe(true) if you trust the input.
	el.isSafe = b

	var walk func(*Element)
	walk = func(element *Element) {
		for _, child := range element.children {
			child.isSafe = b
			walk(child)
		}
	}
	walk(el)
	return el
}

func (el *Element) If(b bool) *Element {
	// If b is false, this element won't be rendered.
	el.isHidden = !b
	return el
}

func (el *Element) TextPrepend(text string) *Element {
	// Adds text before this element's children. Has no effect on void elements like
.
	el.textPrepend = text
	return el
}

func (el *Element) TextAppend(text string) *Element {
	// Adds text after this element's children. Has no effect on void elements like
.
	el.textAppend = text
	return el
}

func (el *Element) Render() string {
	if el.isHidden {
		return ""
	}

	attributes := make([]string, 0)
	for key, val := range el.attributes {
		attributes = append(attributes, fmt.Sprintf(` %v="%v"`, key, val))
	}

	if el.isVoid {
		// Format
		return fmt.Sprintf(
			`<%v%v>`,
			el.tagName,
			strings.Join(attributes, ""),
		)
	} else {
		children := make([]string, 0)
		for _, child := range el.children {
			children = append(children, child.Render())
		}

		return fmt.Sprintf(
			`<%v%v>%v%v%v</%v>`,
			el.tagName,
			strings.Join(attributes, ""),
			el.textPrepend,
			strings.Join(children, ""),
			el.textAppend,
			el.tagName,
		)
	}
}

func (el *Element) RenderIndent(indent string) string {
	if el.isHidden {
		return ""
	}

	attributes := make([]string, 0)
	for key, val := range el.attributes {
		attributes = append(attributes, fmt.Sprintf(` %v="%v"`, key, val))
	}

	// Calculate depth to find indention level
	depth := 0
	parent := el.parent
	for parent != nil {
		parent = parent.parent
		depth++
	}
	nextIndent := strings.Repeat(indent, depth)

	if el.isVoid {
		// Format
		return fmt.Sprintf(
			"%v<%v%v>",
			nextIndent,
			el.tagName,
			strings.Join(attributes, ""),
		)
	} else {
		children := make([]string, 0)
		for _, child := range el.children {
			children = append(children, child.RenderIndent(indent))
		}

		textPrepend := el.textPrepend
		textAppend := el.textAppend

		if !el.isSafe {
			textPrepend = html.EscapeString(textPrepend)
			textAppend = html.EscapeString(textAppend)
		}

		// If element has children, indent text and children.
		// Otherwise, add appended/prepended text on the same line like text.
		if len(children) > 0 {
			// Make sure prepended / appended text is also indented
			if len(textPrepend) > 0 {
				textPrepend = fmt.Sprintf("%v%v%v\n", indent, nextIndent, textPrepend)
			}
			if len(textAppend) > 0 {
				textAppend = fmt.Sprintf("\n%v%v%v\n", indent, nextIndent, textAppend)
			}
			return fmt.Sprintf(
				"%v<%v%v>\n%v%v%v\n%v</%v>",
				nextIndent,
				el.tagName,
				strings.Join(attributes, ""),
				textPrepend,
				strings.Join(children, "\n"),
				textAppend,
				nextIndent,
				el.tagName,
			)
		} else {
			return fmt.Sprintf(
				"%v<%v%v>%v%v</%v>",
				nextIndent,
				el.tagName,
				strings.Join(attributes, ""),
				textPrepend,
				textAppend,
				el.tagName,
			)
		}
	}
}
<|endoftext|>


<commit_before>// Inspired by https://www.goinggo.net/2013/11/using-log-package-in-go.html
package log

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"time"
)

var (
	Debug       *log.Logger
	Info        *log.Logger
	Warning     *log.Logger
	Error       *log.Logger
	Event       *log.Logger
	debugCloser io.Closer
	infoCloser  io.Closer
	warnCloser  io.Closer
	errCloser   io.Closer
	eventCloser io.Closer
)

func initLogger(logger **log.Logger, oldLogCloser *io.Closer, newLogWriter io.WriteCloser, logPrefix string, logFlags int) {
	if newLogWriter == nil {
		*logger = nil
		if *oldLogCloser != nil {
			(*oldLogCloser).Close()
			*oldLogCloser = nil
		}
		return
	}

	if *logger != nil {
		(*logger).SetOutput(newLogWriter)
	} else {
		*logger = log.New(newLogWriter, logPrefix, logFlags)
	}

	if *oldLogCloser != nil {
		(*oldLogCloser).Close()
	}
	*oldLogCloser = newLogWriter
}

// Init initailizes the logs with the given io.WriteClosers. If `Init` was previously called, existing loggers are Closed. If you have loggers which are not Closers or which must not be Closed, wrap them with `log.NopCloser`.
func Init(eventW, errW, warnW, infoW, debugW io.WriteCloser) {
	initLogger(&Debug, &debugCloser, debugW, "DEBUG: ", log.Lshortfile)
	initLogger(&Info, &infoCloser, infoW, "INFO: ", log.Lshortfile)
	initLogger(&Warning, &warnCloser, warnW, "WARNING: ", log.Lshortfile)
	initLogger(&Error, &errCloser, errW, "ERROR: ", log.Lshortfile)
	initLogger(&Event, &eventCloser, eventW, "", 0)
}

const timeFormat = time.RFC3339Nano
const stackFrame = 3

func Errorf(format string, v ...interface{}) {
	if Error == nil {
		return
	}
	Error.Output(stackFrame, time.Now().Format(timeFormat)+": "+fmt.Sprintf(format, v...))
}
func Errorln(v ...interface{}) {
	if Error == nil {
		return
	}
	Error.Output(stackFrame, time.Now().Format(timeFormat)+": "+fmt.Sprintln(v...))
}
func Warnf(format string, v ...interface{}) {
	if Warning == nil {
		return
	}
	Warning.Output(stackFrame, time.Now().Format(timeFormat)+": "+fmt.Sprintf(format, v...))
}
func Warnln(v ...interface{}) {
	if Warning == nil {
		return
	}
	Warning.Output(stackFrame, time.Now().Format(timeFormat)+": "+fmt.Sprintln(v...))
}
func Infof(format string, v ...interface{}) {
	if Info == nil {
		return
	}
	Info.Output(stackFrame, time.Now().Format(timeFormat)+": "+fmt.Sprintf(format, v...))
}
func Infoln(v ...interface{}) {
	if Info == nil {
		return
	}
	Info.Output(stackFrame, time.Now().Format(timeFormat)+": "+fmt.Sprintln(v...))
}
func Debugf(format string, v ...interface{}) {
	if Debug == nil {
		return
	}
	Debug.Output(stackFrame, time.Now().Format(timeFormat)+": "+fmt.Sprintf(format, v...))
}
func Debugln(v ...interface{}) {
	if Debug == nil {
		return
	}
	Debug.Output(stackFrame, time.Now().Format(timeFormat)+": "+fmt.Sprintln(v...))
}

// event log entries (TM event.log, TR access.log, etc)
func Eventf(t time.Time, format string, v ...interface{}) {
	if Event == nil {
		return
	}
	// 1484001185.287 ...
	Event.Printf("%.3f %s", float64(t.Unix())+(float64(t.Nanosecond())/1e9), fmt.Sprintf(format, v...))
}

// Close calls `Close()` on the given Closer, and logs any error. On error, the context is logged, followed by a colon, the error message, and a newline. This is primarily designed to be used in `defer`, for example, `defer log.Close(resp.Body, "readData fetching /foo/bar")`.
func Close(c io.Closer, context string) {
	err := c.Close()
	if err != nil {
		Errorf("%v: %v", context, err)
	}
}

// Closef acts like Close, with a given format string and values, followed by a colon, the error message, and a newline. The given values are not coerced, concatenated, or printed unless an error occurs, so this is more efficient than `Close()`.
func Closef(c io.Closer, contextFormat string, v ...interface{}) {
	err := c.Close()
	if err != nil {
		Errorf(contextFormat, v...)
		Errorf(": %v", err)
	}
}

// Write calls `Write()` on the given Writer, and logs any error. On error, the context is logged, followed by a colon, the error message, and a newline.
func Write(w io.Writer, b []byte, context string) {
	_, err := w.Write(b)
	if err != nil {
		Errorf("%v: %v", context, err)
	}
}

// Writef acts like Write, with a given format string and values, followed by a colon, the error message, and a newline. The given values are not coerced, concatenated, or printed unless an error occurs, so this is more efficient than `Write()`.
func Writef(w io.Writer, b []byte, contextFormat string, v ...interface{}) {
	_, err := w.Write(b)
	if err != nil {
		Errorf(contextFormat, v...)
		Errorf(": %v", err)
	}
}

type nopCloser struct {
	io.Writer
}

func (nopCloser) Close() error { return nil }

func NopCloser(w io.Writer) io.WriteCloser {
	return nopCloser{w}
}

// LogLocation is a location to log to. This may be stdout, stderr, null (/dev/null), or a valid file path.
type LogLocation string

const (
	// LogLocationStdout indicates the stdout IO stream
	LogLocationStdout = "stdout"
	// LogLocationStderr indicates the stderr IO stream
	LogLocationStderr = "stderr"
	// LogLocationNull indicates the null IO stream (/dev/null)
	LogLocationNull = "null"
	//StaticFileDir is the directory that contains static html and js files.
	StaticFileDir = "/opt/traffic_monitor/static/"
)

func GetLogWriter(location LogLocation) (io.WriteCloser, error) {
	switch location {
	case LogLocationStdout:
		return NopCloser(os.Stdout), nil
	case LogLocationStderr:
		return NopCloser(os.Stderr), nil
	case LogLocationNull:
		return NopCloser(ioutil.Discard), nil
	default:
		return os.OpenFile(string(location), os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
	}
}

type Config interface {
	ErrorLog() LogLocation
	WarningLog() LogLocation
	InfoLog() LogLocation
	DebugLog() LogLocation
	EventLog() LogLocation
}

func GetLogWriters(cfg Config) (io.WriteCloser, io.WriteCloser, io.WriteCloser, io.WriteCloser, io.WriteCloser, error) {
	eventLoc := cfg.EventLog()
	errLoc := cfg.ErrorLog()
	warnLoc := cfg.WarningLog()
	infoLoc := cfg.InfoLog()
	debugLoc := cfg.DebugLog()

	eventW, err := GetLogWriter(eventLoc)
	if err != nil {
		return nil, nil, nil, nil, nil, fmt.Errorf("getting log event writer %v: %v", eventLoc, err)
	}
	errW, err := GetLogWriter(errLoc)
	if err != nil {
		return nil, nil, nil, nil, nil, fmt.Errorf("getting log error writer %v: %v", errLoc, err)
	}
	warnW, err := GetLogWriter(warnLoc)
	if err != nil {
		return nil, nil, nil, nil, nil, fmt.Errorf("getting log warning writer %v: %v", warnLoc, err)
	}
	infoW, err := GetLogWriter(infoLoc)
	if err != nil {
		return nil, nil, nil, nil, nil, fmt.Errorf("getting log info writer %v: %v", infoLoc, err)
	}
	debugW, err := GetLogWriter(debugLoc)
	if err != nil {
		return nil, nil, nil, nil, nil, fmt.Errorf("getting log debug writer %v: %v", debugLoc, err)
	}
	return eventW, errW, warnW, infoW, debugW, nil
}

func InitCfg(cfg Config) error {
	eventW, errW, warnW, infoW, debugW, err := GetLogWriters(cfg)
	if err != nil {
		return err
	}
	Init(eventW, errW, warnW, infoW, debugW)
	return nil
}
<commit_msg>Change log init for null loggers to nil<commit_after>// Inspired by https://www.goinggo.net/2013/11/using-log-package-in-go.html
package log

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import (
	"fmt"
	"io"
	"log"
	"os"
	"time"
)

var (
	Debug       *log.Logger
	Info        *log.Logger
	Warning     *log.Logger
	Error       *log.Logger
	Event       *log.Logger
	debugCloser io.Closer
	infoCloser  io.Closer
	warnCloser  io.Closer
	errCloser   io.Closer
	eventCloser io.Closer
)

func initLogger(logger **log.Logger, oldLogCloser *io.Closer, newLogWriter io.WriteCloser, logPrefix string, logFlags int) {
	if newLogWriter == nil {
		*logger = nil
		if *oldLogCloser != nil {
			(*oldLogCloser).Close()
			*oldLogCloser = nil
		}
		return
	}

	if *logger != nil {
		(*logger).SetOutput(newLogWriter)
	} else {
		*logger = log.New(newLogWriter, logPrefix, logFlags)
	}

	if *oldLogCloser != nil {
		(*oldLogCloser).Close()
	}
	*oldLogCloser = newLogWriter
}

// Init initailizes the logs with the given io.WriteClosers. If `Init` was previously called, existing loggers are Closed. If you have loggers which are not Closers or which must not be Closed, wrap them with `log.NopCloser`.
func Init(eventW, errW, warnW, infoW, debugW io.WriteCloser) {
	initLogger(&Debug, &debugCloser, debugW, "DEBUG: ", log.Lshortfile)
	initLogger(&Info, &infoCloser, infoW, "INFO: ", log.Lshortfile)
	initLogger(&Warning, &warnCloser, warnW, "WARNING: ", log.Lshortfile)
	initLogger(&Error, &errCloser, errW, "ERROR: ", log.Lshortfile)
	initLogger(&Event, &eventCloser, eventW, "", 0)
}

const timeFormat = time.RFC3339Nano
const stackFrame = 3

func Errorf(format string, v ...interface{}) {
	if Error == nil {
		return
	}
	Error.Output(stackFrame, time.Now().Format(timeFormat)+": "+fmt.Sprintf(format, v...))
}
func Errorln(v ...interface{}) {
	if Error == nil {
		return
	}
	Error.Output(stackFrame, time.Now().Format(timeFormat)+": "+fmt.Sprintln(v...))
}
func Warnf(format string, v ...interface{}) {
	if Warning == nil {
		return
	}
	Warning.Output(stackFrame, time.Now().Format(timeFormat)+": "+fmt.Sprintf(format, v...))
}
func Warnln(v ...interface{}) {
	if Warning == nil {
		return
	}
	Warning.Output(stackFrame, time.Now().Format(timeFormat)+": "+fmt.Sprintln(v...))
}
func Infof(format string, v ...interface{}) {
	if Info == nil {
		return
	}
	Info.Output(stackFrame, time.Now().Format(timeFormat)+": "+fmt.Sprintf(format, v...))
}
func Infoln(v ...interface{}) {
	if Info == nil {
		return
	}
	Info.Output(stackFrame, time.Now().Format(timeFormat)+": "+fmt.Sprintln(v...))
}
func Debugf(format string, v ...interface{}) {
	if Debug == nil {
		return
	}
	Debug.Output(stackFrame, time.Now().Format(timeFormat)+": "+fmt.Sprintf(format, v...))
}
func Debugln(v ...interface{}) {
	if Debug == nil {
		return
	}
	Debug.Output(stackFrame, time.Now().Format(timeFormat)+": "+fmt.Sprintln(v...))
}

// event log entries (TM event.log, TR access.log, etc)
func Eventf(t time.Time, format string, v ...interface{}) {
	if Event == nil {
		return
	}
	// 1484001185.287 ...
	Event.Printf("%.3f %s", float64(t.Unix())+(float64(t.Nanosecond())/1e9), fmt.Sprintf(format, v...))
}

// Close calls `Close()` on the given Closer, and logs any error. On error, the context is logged, followed by a colon, the error message, and a newline. This is primarily designed to be used in `defer`, for example, `defer log.Close(resp.Body, "readData fetching /foo/bar")`.
func Close(c io.Closer, context string) {
	err := c.Close()
	if err != nil {
		Errorf("%v: %v", context, err)
	}
}

// Closef acts like Close, with a given format string and values, followed by a colon, the error message, and a newline. The given values are not coerced, concatenated, or printed unless an error occurs, so this is more efficient than `Close()`.
func Closef(c io.Closer, contextFormat string, v ...interface{}) {
	err := c.Close()
	if err != nil {
		Errorf(contextFormat, v...)
		Errorf(": %v", err)
	}
}

// Write calls `Write()` on the given Writer, and logs any error. On error, the context is logged, followed by a colon, the error message, and a newline.
func Write(w io.Writer, b []byte, context string) {
	_, err := w.Write(b)
	if err != nil {
		Errorf("%v: %v", context, err)
	}
}

// Writef acts like Write, with a given format string and values, followed by a colon, the error message, and a newline. The given values are not coerced, concatenated, or printed unless an error occurs, so this is more efficient than `Write()`.
func Writef(w io.Writer, b []byte, contextFormat string, v ...interface{}) {
	_, err := w.Write(b)
	if err != nil {
		Errorf(contextFormat, v...)
		Errorf(": %v", err)
	}
}

type nopCloser struct {
	io.Writer
}

func (nopCloser) Close() error { return nil }

func NopCloser(w io.Writer) io.WriteCloser {
	return nopCloser{w}
}

// LogLocation is a location to log to. This may be stdout, stderr, null (/dev/null), or a valid file path.
type LogLocation string

const (
	// LogLocationStdout indicates the stdout IO stream
	LogLocationStdout = "stdout"
	// LogLocationStderr indicates the stderr IO stream
	LogLocationStderr = "stderr"
	// LogLocationNull indicates the null IO stream (/dev/null)
	LogLocationNull = "null"
	//StaticFileDir is the directory that contains static html and js files.
	StaticFileDir = "/opt/traffic_monitor/static/"
)

func GetLogWriter(location LogLocation) (io.WriteCloser, error) {
	switch location {
	case LogLocationStdout:
		return NopCloser(os.Stdout), nil
	case LogLocationStderr:
		return NopCloser(os.Stderr), nil
	case LogLocationNull:
		fallthrough
	case "":
		return nil, nil
	default:
		return os.OpenFile(string(location), os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
	}
}

type Config interface {
	ErrorLog() LogLocation
	WarningLog() LogLocation
	InfoLog() LogLocation
	DebugLog() LogLocation
	EventLog() LogLocation
}

func GetLogWriters(cfg Config) (io.WriteCloser, io.WriteCloser, io.WriteCloser, io.WriteCloser, io.WriteCloser, error) {
	eventLoc := cfg.EventLog()
	errLoc := cfg.ErrorLog()
	warnLoc := cfg.WarningLog()
	infoLoc := cfg.InfoLog()
	debugLoc := cfg.DebugLog()

	eventW, err := GetLogWriter(eventLoc)
	if err != nil {
		return nil, nil, nil, nil, nil, fmt.Errorf("getting log event writer %v: %v", eventLoc, err)
	}
	errW, err := GetLogWriter(errLoc)
	if err != nil {
		return nil, nil, nil, nil, nil, fmt.Errorf("getting log error writer %v: %v", errLoc, err)
	}
	warnW, err := GetLogWriter(warnLoc)
	if err != nil {
		return nil, nil, nil, nil, nil, fmt.Errorf("getting log warning writer %v: %v", warnLoc, err)
	}
	infoW, err := GetLogWriter(infoLoc)
	if err != nil {
		return nil, nil, nil, nil, nil, fmt.Errorf("getting log info writer %v: %v", infoLoc, err)
	}
	debugW, err := GetLogWriter(debugLoc)
	if err != nil {
		return nil, nil, nil, nil, nil, fmt.Errorf("getting log debug writer %v: %v", debugLoc, err)
	}
	return eventW, errW, warnW, infoW, debugW, nil
}

func InitCfg(cfg Config) error {
	eventW, errW, warnW, infoW, debugW, err := GetLogWriters(cfg)
	if err != nil {
		return err
	}
	Init(eventW, errW, warnW, infoW, debugW)
	return nil
}
<|endoftext|>


<commit_before>package object

import (
	"path"

	"golang.org/x/exp/mmap"
	. "gopkg.in/check.v1"
	"gopkg.in/src-d/go-git-fixtures.v3"
	"gopkg.in/src-d/go-git.v4/plumbing"
	"gopkg.in/src-d/go-git.v4/plumbing/cache"
	"gopkg.in/src-d/go-git.v4/plumbing/format/commitgraph"
	"gopkg.in/src-d/go-git.v4/plumbing/format/packfile"
	"gopkg.in/src-d/go-git.v4/storage/filesystem"
)

type CommitNodeSuite struct {
	fixtures.Suite
}

var _ = Suite(&CommitNodeSuite{})

func testWalker(c *C, nodeIndex CommitNodeIndex) {
	head, err := nodeIndex.Get(plumbing.NewHash("b9d69064b190e7aedccf84731ca1d917871f8a1c"))
	c.Assert(err, IsNil)

	iter := NewCommitNodeIterCTime(
		head,
		nil,
		nil,
	)

	var commits []CommitNode
	iter.ForEach(func(c CommitNode) error {
		commits = append(commits, c)
		return nil
	})

	c.Assert(commits, HasLen, 9)

	expected := []string{
		"b9d69064b190e7aedccf84731ca1d917871f8a1c",
		"6f6c5d2be7852c782be1dd13e36496dd7ad39560",
		"a45273fe2d63300e1962a9e26a6b15c276cd7082",
		"c0edf780dd0da6a65a7a49a86032fcf8a0c2d467",
		"bb13916df33ed23004c3ce9ed3b8487528e655c1",
		"03d2c021ff68954cf3ef0a36825e194a4b98f981",
		"ce275064ad67d51e99f026084e20827901a8361c",
		"e713b52d7e13807e87a002e812041f248db3f643",
		"347c91919944a68e9413581a1bc15519550a3afe",
	}
	for i, commit := range commits {
		c.Assert(commit.ID().String(), Equals, expected[i])
	}
}

func testParents(c *C, nodeIndex CommitNodeIndex) {
	merge3, err := nodeIndex.Get(plumbing.NewHash("6f6c5d2be7852c782be1dd13e36496dd7ad39560"))
	c.Assert(err, IsNil)

	var parents []CommitNode
	merge3.ParentNodes().ForEach(func(c CommitNode) error {
		parents = append(parents, c)
		return nil
	})

	c.Assert(parents, HasLen, 3)

	expected := []string{
		"ce275064ad67d51e99f026084e20827901a8361c",
		"bb13916df33ed23004c3ce9ed3b8487528e655c1",
		"a45273fe2d63300e1962a9e26a6b15c276cd7082",
	}
	for i, parent := range parents {
		c.Assert(parent.ID().String(), Equals, expected[i])
	}
}

func (s *CommitNodeSuite) TestObjectGraph(c *C) {
	f := fixtures.ByTag("commit-graph").One()
	storer := filesystem.NewStorage(f.DotGit(), cache.NewObjectLRUDefault())
	p := f.Packfile()
	defer p.Close()
	err := packfile.UpdateObjectStorage(storer, p)
	c.Assert(err, IsNil)

	nodeIndex := NewObjectCommitNodeIndex(storer)
	testWalker(c, nodeIndex)
	testParents(c, nodeIndex)
}

func (s *CommitNodeSuite) TestCommitGraph(c *C) {
	f := fixtures.ByTag("commit-graph").One()
	dotgit := f.DotGit()
	storer := filesystem.NewStorage(dotgit, cache.NewObjectLRUDefault())
	reader, err := mmap.Open(path.Join(dotgit.Root(), "objects", "info", "commit-graph"))
	c.Assert(err, IsNil)
	defer reader.Close()
	index, err := commitgraph.OpenFileIndex(reader)
	c.Assert(err, IsNil)

	nodeIndex := NewGraphCommitNodeIndex(index, storer)
	testWalker(c, nodeIndex)
	testParents(c, nodeIndex)
}

func (s *CommitNodeSuite) TestMixedGraph(c *C) {
	// Unpack the original repository with pack file
	f := fixtures.ByTag("commit-graph").One()
	dotgit := f.DotGit()
	storer := filesystem.NewStorage(dotgit, cache.NewObjectLRUDefault())
	p := f.Packfile()
	defer p.Close()
	err := packfile.UpdateObjectStorage(storer, p)
	c.Assert(err, IsNil)

	// Take the commit-graph file and copy it to memory index without the last commit
	reader, err := mmap.Open(path.Join(dotgit.Root(), "objects", "info", "commit-graph"))
	c.Assert(err, IsNil)
	defer reader.Close()
	fileIndex, err := commitgraph.OpenFileIndex(reader)
	c.Assert(err, IsNil)
	memoryIndex := commitgraph.NewMemoryIndex()
	for i, hash := range fileIndex.Hashes() {
		if hash.String() != "b9d69064b190e7aedccf84731ca1d917871f8a1c" {
			node, err := fileIndex.GetNodeByIndex(i)
			c.Assert(err, IsNil)
			memoryIndex.Add(hash, node)
		}
	}

	nodeIndex := NewGraphCommitNodeIndex(memoryIndex, storer)
	testWalker(c, nodeIndex)
	testParents(c, nodeIndex)
}
<commit_msg>Add test for CommitNode.Commit() and CommitNode.Tree()<commit_after>package object

import (
	"path"

	. "gopkg.in/check.v1"
	"gopkg.in/src-d/go-git-fixtures.v3"
	"gopkg.in/src-d/go-git.v4/plumbing"
	"gopkg.in/src-d/go-git.v4/plumbing/cache"
	"gopkg.in/src-d/go-git.v4/plumbing/format/commitgraph"
	"gopkg.in/src-d/go-git.v4/plumbing/format/packfile"
	"gopkg.in/src-d/go-git.v4/storage/filesystem"
)

type CommitNodeSuite struct {
	fixtures.Suite
}

var _ = Suite(&CommitNodeSuite{})

func unpackRepositry(f *fixtures.Fixture) *filesystem.Storage {
	storer := filesystem.NewStorage(f.DotGit(), cache.NewObjectLRUDefault())
	p := f.Packfile()
	defer p.Close()
	packfile.UpdateObjectStorage(storer, p)
	return storer
}

func testWalker(c *C, nodeIndex CommitNodeIndex) {
	head, err := nodeIndex.Get(plumbing.NewHash("b9d69064b190e7aedccf84731ca1d917871f8a1c"))
	c.Assert(err, IsNil)

	iter := NewCommitNodeIterCTime(
		head,
		nil,
		nil,
	)

	var commits []CommitNode
	iter.ForEach(func(c CommitNode) error {
		commits = append(commits, c)
		return nil
	})

	c.Assert(commits, HasLen, 9)

	expected := []string{
		"b9d69064b190e7aedccf84731ca1d917871f8a1c",
		"6f6c5d2be7852c782be1dd13e36496dd7ad39560",
		"a45273fe2d63300e1962a9e26a6b15c276cd7082",
		"c0edf780dd0da6a65a7a49a86032fcf8a0c2d467",
		"bb13916df33ed23004c3ce9ed3b8487528e655c1",
		"03d2c021ff68954cf3ef0a36825e194a4b98f981",
		"ce275064ad67d51e99f026084e20827901a8361c",
		"e713b52d7e13807e87a002e812041f248db3f643",
		"347c91919944a68e9413581a1bc15519550a3afe",
	}
	for i, commit := range commits {
		c.Assert(commit.ID().String(), Equals, expected[i])
	}
}

func testParents(c *C, nodeIndex CommitNodeIndex) {
	merge3, err := nodeIndex.Get(plumbing.NewHash("6f6c5d2be7852c782be1dd13e36496dd7ad39560"))
	c.Assert(err, IsNil)

	var parents []CommitNode
	merge3.ParentNodes().ForEach(func(c CommitNode) error {
		parents = append(parents, c)
		return nil
	})

	c.Assert(parents, HasLen, 3)

	expected := []string{
		"ce275064ad67d51e99f026084e20827901a8361c",
		"bb13916df33ed23004c3ce9ed3b8487528e655c1",
		"a45273fe2d63300e1962a9e26a6b15c276cd7082",
	}
	for i, parent := range parents {
		c.Assert(parent.ID().String(), Equals, expected[i])
	}
}

func testCommitAndTree(c *C, nodeIndex CommitNodeIndex) {
	merge3node, err := nodeIndex.Get(plumbing.NewHash("6f6c5d2be7852c782be1dd13e36496dd7ad39560"))
	c.Assert(err, IsNil)
	merge3commit, err := merge3node.Commit()
	c.Assert(err, IsNil)
	c.Assert(merge3node.ID().String(), Equals, merge3commit.ID().String())
	tree, err := merge3node.Tree()
	c.Assert(err, IsNil)
	c.Assert(tree.ID().String(), Equals, merge3commit.TreeHash.String())
}

func (s *CommitNodeSuite) TestObjectGraph(c *C) {
	f := fixtures.ByTag("commit-graph").One()
	storer := unpackRepositry(f)

	nodeIndex := NewObjectCommitNodeIndex(storer)
	testWalker(c, nodeIndex)
	testParents(c, nodeIndex)
	testCommitAndTree(c, nodeIndex)
}

func (s *CommitNodeSuite) TestCommitGraph(c *C) {
	f := fixtures.ByTag("commit-graph").One()
	storer := unpackRepositry(f)
	reader, err := storer.Filesystem().Open(path.Join("objects", "info", "commit-graph"))
	c.Assert(err, IsNil)
	defer reader.Close()
	index, err := commitgraph.OpenFileIndex(reader)
	c.Assert(err, IsNil)

	nodeIndex := NewGraphCommitNodeIndex(index, storer)
	testWalker(c, nodeIndex)
	testParents(c, nodeIndex)
	testCommitAndTree(c, nodeIndex)
}

func (s *CommitNodeSuite) TestMixedGraph(c *C) {
	f := fixtures.ByTag("commit-graph").One()
	storer := unpackRepositry(f)

	// Take the commit-graph file and copy it to memory index without the last commit
	reader, err := storer.Filesystem().Open(path.Join("objects", "info", "commit-graph"))
	c.Assert(err, IsNil)
	defer reader.Close()
	fileIndex, err := commitgraph.OpenFileIndex(reader)
	c.Assert(err, IsNil)
	memoryIndex := commitgraph.NewMemoryIndex()
	for i, hash := range fileIndex.Hashes() {
		if hash.String() != "b9d69064b190e7aedccf84731ca1d917871f8a1c" {
			node, err := fileIndex.GetNodeByIndex(i)
			c.Assert(err, IsNil)
			memoryIndex.Add(hash, node)
		}
	}

	nodeIndex := NewGraphCommitNodeIndex(memoryIndex, storer)
	testWalker(c, nodeIndex)
	testParents(c, nodeIndex)
	testCommitAndTree(c, nodeIndex)
}
<|endoftext|>


<commit_before>package app

import (
	"log"

	"github.com/codegangsta/cli"
	"github.com/garlsecurity/securepassctl"
	"github.com/garlsecurity/securepassctl/spctl/service"
)

func init() {
	Command.Subcommands = append(Command.Subcommands,
		cli.Command{
			Name:        "mod",
			Usage:       "modify application",
			ArgsUsage:   "APP_ID",
			Description: "Modify an application in SecurePass",
			Action:      ActionMod,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "label, l",
					Usage: "Label",
				},
				cli.StringFlag{
					Name:  "ipv4, 4",
					Usage: "restrict to IPv4 network (default: 0.0.0.0/0)",
				},
				cli.StringFlag{
					Name:  "ipv6, 6",
					Usage: "restrict to IPv6 network (default: ::/0)",
				},
				cli.StringFlag{
					Name:  "group, g",
					Usage: "Group name (restriction)",
				},
				cli.BoolFlag{
					Name:  "write, w",
					Usage: "Write capabilities (default: false)",
				},
				cli.BoolTFlag{
					Name:  "read, r",
					Usage: "Read capabilities (default: true)",
				},
				cli.BoolFlag{
					Name:  "privacy, p",
					Usage: "Enable privacy mode (default: false)",
				},
			},
		})
}

// ActionMod provides the add subcommand
func ActionMod(c *cli.Context) {
	if len(c.Args()) != 1 {
		log.Fatal("error: must specify an app id")
	}
	app := c.Args()[0]
	_, err := service.Service.AppMod(app, &securepassctl.ApplicationDescriptor{
		Label:            c.String("label"),
		Group:            c.String("group"),
		Realm:            c.String("realm"),
		Write:            c.Bool("write"),
		Privacy:          c.Bool("privacy"),
		AllowNetworkIPv4: c.String("ipv4"),
		AllowNetworkIPv6: c.String("ipv6"),
	})
	if err != nil {
		log.Fatalf("error: %v", err)
	}

	log.Println()
}
<commit_msg>Remove debugging leftover<commit_after>package app

import (
	"log"

	"github.com/codegangsta/cli"
	"github.com/garlsecurity/securepassctl"
	"github.com/garlsecurity/securepassctl/spctl/service"
)

func init() {
	Command.Subcommands = append(Command.Subcommands,
		cli.Command{
			Name:        "mod",
			Usage:       "modify application",
			ArgsUsage:   "APP_ID",
			Description: "Modify an application in SecurePass",
			Action:      ActionMod,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "label, l",
					Usage: "Label",
				},
				cli.StringFlag{
					Name:  "ipv4, 4",
					Usage: "restrict to IPv4 network (default: 0.0.0.0/0)",
				},
				cli.StringFlag{
					Name:  "ipv6, 6",
					Usage: "restrict to IPv6 network (default: ::/0)",
				},
				cli.StringFlag{
					Name:  "group, g",
					Usage: "Group name (restriction)",
				},
				cli.BoolFlag{
					Name:  "write, w",
					Usage: "Write capabilities (default: false)",
				},
				cli.BoolTFlag{
					Name:  "read, r",
					Usage: "Read capabilities (default: true)",
				},
				cli.BoolFlag{
					Name:  "privacy, p",
					Usage: "Enable privacy mode (default: false)",
				},
			},
		})
}

// ActionMod provides the add subcommand
func ActionMod(c *cli.Context) {
	if len(c.Args()) != 1 {
		log.Fatal("error: must specify an app id")
	}
	app := c.Args()[0]
	_, err := service.Service.AppMod(app, &securepassctl.ApplicationDescriptor{
		Label:            c.String("label"),
		Group:            c.String("group"),
		Realm:            c.String("realm"),
		Write:            c.Bool("write"),
		Privacy:          c.Bool("privacy"),
		AllowNetworkIPv4: c.String("ipv4"),
		AllowNetworkIPv6: c.String("ipv6"),
	})
	if err != nil {
		log.Fatalf("error: %v", err)
	}
}
<|endoftext|>