<commit_before>// Copyright (c) 2017, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package interp

import (
	"context"
	"fmt"
	"runtime"
	"sort"
	"strings"

	"mvdan.cc/sh/syntax"
)

type Environ interface {
	Get(name string) (value string, exists bool)
	Set(name, value string)
	Delete(name string)
	Names() []string
	Copy() Environ
}

type mapEnviron struct {
	names  []string
	values map[string]string
}

func (m *mapEnviron) Get(name string) (string, bool) {
	val, ok := m.values[name]
	return val, ok
}

func (m *mapEnviron) Set(name, value string) {
	_, ok := m.values[name]
	if !ok {
		m.names = append(m.names, name)
		sort.Strings(m.names)
	}
	m.values[name] = value
}

func (m *mapEnviron) Delete(name string) {
	if _, ok := m.values[name]; !ok {
		return
	}
	delete(m.values, name)
	for i, iname := range m.names {
		if iname == name {
			m.names = append(m.names[:i], m.names[i+1:]...)
			return
		}
	}
}

func (m *mapEnviron) Names() []string {
	return m.names
}

func (m *mapEnviron) Copy() Environ {
	m2 := &mapEnviron{
		names:  make([]string, len(m.names)),
		values: make(map[string]string, len(m.values)),
	}
	copy(m2.names, m.names)
	for name, val := range m.values {
		m2.values[name] = val
	}
	return m2
}

func execEnv(env Environ) []string {
	names := env.Names()
	list := make([]string, len(names))
	for i, name := range names {
		val, _ := env.Get(name)
		list[i] = name + "=" + val
	}
	return list
}

func EnvFromList(list []string) (Environ, error) {
	m := mapEnviron{
		names:  make([]string, 0, len(list)),
		values: make(map[string]string, len(list)),
	}
	for _, kv := range list {
		i := strings.IndexByte(kv, '=')
		if i < 0 {
			return nil, fmt.Errorf("env not in the form key=value: %q", kv)
		}
		name, val := kv[:i], kv[i+1:]
		if runtime.GOOS == "windows" {
			name = strings.ToUpper(name)
		}
		m.names = append(m.names, name)
		m.values[name] = val
	}
	sort.Strings(m.names)
	return &m, nil
}

type FuncEnviron func(string) string

func (f FuncEnviron) Get(name string) (string, bool) {
	val := f(name)
	return val, val != ""
}

func (f FuncEnviron) Set(name, value string) {}
func (f FuncEnviron) Delete(name string)     {}
func (f FuncEnviron) Names() []string        { return nil }
func (f FuncEnviron) Copy() Environ          { return f }

type Variable struct {
	Local    bool
	Exported bool
	ReadOnly bool
	NameRef  bool
	Value    VarValue
}

// VarValue is one of:
//
//     StringVal
//     IndexArray
//     AssocArray
type VarValue interface{}

type StringVal string

type IndexArray []string

type AssocArray map[string]string

func (r *Runner) lookupVar(name string) (Variable, bool) {
	if name == "" {
		panic("variable name must not be empty")
	}
	if val, e := r.cmdVars[name]; e {
		return Variable{Value: StringVal(val)}, true
	}
	if vr, e := r.funcVars[name]; e {
		return vr, true
	}
	if vr, e := r.Vars[name]; e {
		return vr, true
	}
	if str, e := r.Env.Get(name); e {
		return Variable{Value: StringVal(str)}, true
	}
	if runtime.GOOS == "windows" {
		upper := strings.ToUpper(name)
		if str, e := r.Env.Get(upper); e {
			return Variable{Value: StringVal(str)}, true
		}
	}
	if r.opts[optNoUnset] {
		r.errf("%s: unbound variable\n", name)
		r.setErr(ShellExitStatus(1))
	}
	return Variable{}, false
}

func (r *Runner) getVar(name string) string {
	val, _ := r.lookupVar(name)
	return r.varStr(val, 0)
}

func (r *Runner) delVar(name string) {
	val, _ := r.lookupVar(name)
	if val.ReadOnly {
		r.errf("%s: readonly variable\n", name)
		r.exit = 1
		return
	}
	delete(r.Vars, name)
	delete(r.funcVars, name)
	delete(r.cmdVars, name)
	r.Env.Delete(name)
}

// maxNameRefDepth defines the maximum number of times to follow
// references when expanding a variable. Otherwise, simple name
// reference loops could crash the interpreter quite easily.
const maxNameRefDepth = 100

func (r *Runner) varStr(vr Variable, depth int) string {
	if depth > maxNameRefDepth {
		return ""
	}
	switch x := vr.Value.(type) {
	case StringVal:
		if vr.NameRef {
			vr, _ = r.lookupVar(string(x))
			return r.varStr(vr, depth+1)
		}
		return string(x)
	case IndexArray:
		if len(x) > 0 {
			return x[0]
		}
	case AssocArray:
		// nothing to do
	}
	return ""
}

func (r *Runner) varInd(ctx context.Context, vr Variable, e syntax.ArithmExpr, depth int) string {
	if depth > maxNameRefDepth {
		return ""
	}
	switch x := vr.Value.(type) {
	case StringVal:
		if vr.NameRef {
			vr, _ = r.lookupVar(string(x))
			return r.varInd(ctx, vr, e, depth+1)
		}
		if r.arithm(ctx, e) == 0 {
			return string(x)
		}
	case IndexArray:
		switch anyOfLit(e, "@", "*") {
		case "@":
			return strings.Join(x, " ")
		case "*":
			return strings.Join(x, r.ifsJoin)
		}
		i := r.arithm(ctx, e)
		if len(x) > 0 {
			return x[i]
		}
	case AssocArray:
		if lit := anyOfLit(e, "@", "*"); lit != "" {
			var strs IndexArray
			keys := make([]string, 0, len(x))
			for k := range x {
				keys = append(keys, k)
			}
			sort.Strings(keys)
			for _, k := range keys {
				strs = append(strs, x[k])
			}
			if lit == "*" {
				return strings.Join(strs, r.ifsJoin)
			}
			return strings.Join(strs, " ")
		}
		return x[r.loneWord(ctx, e.(*syntax.Word))]
	}
	return ""
}

func (r *Runner) setVarString(ctx context.Context, name, val string) {
	r.setVar(ctx, name, nil, Variable{Value: StringVal(val)})
}

func (r *Runner) setVarInternal(name string, vr Variable) {
	if _, ok := vr.Value.(StringVal); ok {
		if r.opts[optAllExport] {
			vr.Exported = true
		}
	} else {
		vr.Exported = false
	}
	if vr.Local {
		if r.funcVars == nil {
			r.funcVars = make(map[string]Variable)
		}
		r.funcVars[name] = vr
	} else {
		r.Vars[name] = vr
	}
	if name == "IFS" {
		r.ifsUpdated()
	}
}

func (r *Runner) setVar(ctx context.Context, name string, index syntax.ArithmExpr, vr Variable) {
	cur, _ := r.lookupVar(name)
	if cur.ReadOnly {
		r.errf("%s: readonly variable\n", name)
		r.exit = 1
		return
	}
	_, isIndexArray := cur.Value.(IndexArray)
	_, isAssocArray := cur.Value.(AssocArray)

	if _, ok := vr.Value.(StringVal); ok && index == nil {
		// When assigning a string to an array, fall back to the
		// zero value for the index.
		if isIndexArray {
			index = &syntax.Word{Parts: []syntax.WordPart{
				&syntax.Lit{Value: "0"},
			}}
		} else if isAssocArray {
			index = &syntax.Word{Parts: []syntax.WordPart{
				&syntax.DblQuoted{},
			}}
		}
	}
	if index == nil {
		r.setVarInternal(name, vr)
		return
	}

	// from the syntax package, we know that val must be a string if
	// index is non-nil; nested arrays are forbidden.
	valStr := string(vr.Value.(StringVal))

	// if the existing variable is already an AssocArray, try our best
	// to convert the key to a string
	if isAssocArray {
		amap := cur.Value.(AssocArray)
		w, ok := index.(*syntax.Word)
		if !ok {
			return
		}
		k := r.loneWord(ctx, w)
		amap[k] = valStr
		cur.Value = amap
		r.setVarInternal(name, cur)
		return
	}
	var list IndexArray
	switch x := cur.Value.(type) {
	case StringVal:
		list = append(list, string(x))
	case IndexArray:
		list = x
	case AssocArray: // done above
	}
	k := r.arithm(ctx, index)
	for len(list) < k+1 {
		list = append(list, "")
	}
	list[k] = valStr
	cur.Value = list
	r.setVarInternal(name, cur)
}

func (r *Runner) setFunc(name string, body *syntax.Stmt) {
	if r.Funcs == nil {
		r.Funcs = make(map[string]*syntax.Stmt, 4)
	}
	r.Funcs[name] = body
}

func stringIndex(index syntax.ArithmExpr) bool {
	w, ok := index.(*syntax.Word)
	if !ok || len(w.Parts) != 1 {
		return false
	}
	switch w.Parts[0].(type) {
	case *syntax.DblQuoted, *syntax.SglQuoted:
		return true
	}
	return false
}

func (r *Runner) assignVal(ctx context.Context, as *syntax.Assign, valType string) VarValue {
	prev, prevOk := r.lookupVar(as.Name.Value)
	if as.Naked {
		return prev.Value
	}
	if as.Value != nil {
		s := r.loneWord(ctx, as.Value)
		if !as.Append || !prevOk {
			return StringVal(s)
		}
		switch x := prev.Value.(type) {
		case StringVal:
			return x + StringVal(s)
		case IndexArray:
			if len(x) == 0 {
				x = append(x, "")
			}
			x[0] += s
			return x
		case AssocArray:
			// TODO
		}
		return StringVal(s)
	}
	if as.Array == nil {
		return nil
	}
	elems := as.Array.Elems
	if valType == "" {
		if len(elems) == 0 || !stringIndex(elems[0].Index) {
			valType = "-a" // indexed
		} else {
			valType = "-A" // associative
		}
	}
	if valType == "-A" {
		// associative array
		amap := AssocArray(make(map[string]string, len(elems)))
		for _, elem := range elems {
			k := r.loneWord(ctx, elem.Index.(*syntax.Word))
			amap[k] = r.loneWord(ctx, elem.Value)
		}
		if !as.Append || !prevOk {
			return amap
		}
		// TODO
		return amap
	}
	// indexed array
	maxIndex := len(elems) - 1
	indexes := make([]int, len(elems))
	for i, elem := range elems {
		if elem.Index == nil {
			indexes[i] = i
			continue
		}
		k := r.arithm(ctx, elem.Index)
		indexes[i] = k
		if k > maxIndex {
			maxIndex = k
		}
	}
	strs := make([]string, maxIndex+1)
	for i, elem := range elems {
		strs[indexes[i]] = r.loneWord(ctx, elem.Value)
	}
	if !as.Append || !prevOk {
		return IndexArray(strs)
	}
	switch x := prev.Value.(type) {
	case StringVal:
		prevList := IndexArray([]string{string(x)})
		return append(prevList, strs...)
	case IndexArray:
		return append(x, strs...)
	case AssocArray:
		// TODO
	}
	return IndexArray(strs)
}

func (r *Runner) ifsUpdated() {
	runes := r.getVar("IFS")
	r.ifsJoin = ""
	if len(runes) > 0 {
		r.ifsJoin = runes[:1]
	}
	r.ifsRune = func(r rune) bool {
		for _, r2 := range runes {
			if r == r2 {
				return true
			}
		}
		return false
	}
}

func (r *Runner) namesByPrefix(prefix string) []string {
	var names []string
	for _, name := range r.Env.Names() {
		if strings.HasPrefix(name, prefix) {
			names = append(names, name)
		}
	}
	for name := range r.Vars {
		if strings.HasPrefix(name, prefix) {
			names = append(names, name)
		}
	}
	return names
}
<commit_msg>interp: replace Environ.Names with Each<commit_after>// Copyright (c) 2017, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package interp

import (
	"context"
	"fmt"
	"runtime"
	"sort"
	"strings"

	"mvdan.cc/sh/syntax"
)

type Environ interface {
	Get(name string) (value string, exists bool)
	Set(name, value string)
	Delete(name string)
	Each(func(name, value string) bool)
	Copy() Environ
}

type mapEnviron struct {
	values map[string]string
}

func (m *mapEnviron) Get(name string) (string, bool) {
	val, ok := m.values[name]
	return val, ok
}

func (m *mapEnviron) Set(name, value string) {
	m.values[name] = value
}

func (m *mapEnviron) Delete(name string) {
	delete(m.values, name)
}

func (m *mapEnviron) Each(f func(name, value string) bool) {
	for name, value := range m.values {
		if !f(name, value) {
			break
		}
	}
}

func (m *mapEnviron) Copy() Environ {
	m2 := &mapEnviron{
		values: make(map[string]string, len(m.values)),
	}
	for name, val := range m.values {
		m2.values[name] = val
	}
	return m2
}

func execEnv(env Environ) []string {
	list := make([]string, 32)
	env.Each(func(name, value string) bool {
		list = append(list, name+"="+value)
		return true
	})
	return list
}

func EnvFromList(list []string) (Environ, error) {
	m := mapEnviron{
		values: make(map[string]string, len(list)),
	}
	for _, kv := range list {
		i := strings.IndexByte(kv, '=')
		if i < 0 {
			return nil, fmt.Errorf("env not in the form key=value: %q", kv)
		}
		name, val := kv[:i], kv[i+1:]
		if runtime.GOOS == "windows" {
			name = strings.ToUpper(name)
		}
		m.values[name] = val
	}
	return &m, nil
}

type FuncEnviron func(string) string

func (f FuncEnviron) Get(name string) (string, bool) {
	val := f(name)
	return val, val != ""
}

func (f FuncEnviron) Set(name, value string)             {}
func (f FuncEnviron) Delete(name string)                 {}
func (f FuncEnviron) Each(func(name, value string) bool) {}
func (f FuncEnviron) Copy() Environ                      { return f }

type Variable struct {
	Local    bool
	Exported bool
	ReadOnly bool
	NameRef  bool
	Value    VarValue
}

// VarValue is one of:
//
//     StringVal
//     IndexArray
//     AssocArray
type VarValue interface{}

type StringVal string

type IndexArray []string

type AssocArray map[string]string

func (r *Runner) lookupVar(name string) (Variable, bool) {
	if name == "" {
		panic("variable name must not be empty")
	}
	if val, e := r.cmdVars[name]; e {
		return Variable{Value: StringVal(val)}, true
	}
	if vr, e := r.funcVars[name]; e {
		return vr, true
	}
	if vr, e := r.Vars[name]; e {
		return vr, true
	}
	if str, e := r.Env.Get(name); e {
		return Variable{Value: StringVal(str)}, true
	}
	if runtime.GOOS == "windows" {
		upper := strings.ToUpper(name)
		if str, e := r.Env.Get(upper); e {
			return Variable{Value: StringVal(str)}, true
		}
	}
	if r.opts[optNoUnset] {
		r.errf("%s: unbound variable\n", name)
		r.setErr(ShellExitStatus(1))
	}
	return Variable{}, false
}

func (r *Runner) getVar(name string) string {
	val, _ := r.lookupVar(name)
	return r.varStr(val, 0)
}

func (r *Runner) delVar(name string) {
	val, _ := r.lookupVar(name)
	if val.ReadOnly {
		r.errf("%s: readonly variable\n", name)
		r.exit = 1
		return
	}
	delete(r.Vars, name)
	delete(r.funcVars, name)
	delete(r.cmdVars, name)
	r.Env.Delete(name)
}

// maxNameRefDepth defines the maximum number of times to follow
// references when expanding a variable. Otherwise, simple name
// reference loops could crash the interpreter quite easily.
const maxNameRefDepth = 100

func (r *Runner) varStr(vr Variable, depth int) string {
	if depth > maxNameRefDepth {
		return ""
	}
	switch x := vr.Value.(type) {
	case StringVal:
		if vr.NameRef {
			vr, _ = r.lookupVar(string(x))
			return r.varStr(vr, depth+1)
		}
		return string(x)
	case IndexArray:
		if len(x) > 0 {
			return x[0]
		}
	case AssocArray:
		// nothing to do
	}
	return ""
}

func (r *Runner) varInd(ctx context.Context, vr Variable, e syntax.ArithmExpr, depth int) string {
	if depth > maxNameRefDepth {
		return ""
	}
	switch x := vr.Value.(type) {
	case StringVal:
		if vr.NameRef {
			vr, _ = r.lookupVar(string(x))
			return r.varInd(ctx, vr, e, depth+1)
		}
		if r.arithm(ctx, e) == 0 {
			return string(x)
		}
	case IndexArray:
		switch anyOfLit(e, "@", "*") {
		case "@":
			return strings.Join(x, " ")
		case "*":
			return strings.Join(x, r.ifsJoin)
		}
		i := r.arithm(ctx, e)
		if len(x) > 0 {
			return x[i]
		}
	case AssocArray:
		if lit := anyOfLit(e, "@", "*"); lit != "" {
			var strs IndexArray
			keys := make([]string, 0, len(x))
			for k := range x {
				keys = append(keys, k)
			}
			sort.Strings(keys)
			for _, k := range keys {
				strs = append(strs, x[k])
			}
			if lit == "*" {
				return strings.Join(strs, r.ifsJoin)
			}
			return strings.Join(strs, " ")
		}
		return x[r.loneWord(ctx, e.(*syntax.Word))]
	}
	return ""
}

func (r *Runner) setVarString(ctx context.Context, name, val string) {
	r.setVar(ctx, name, nil, Variable{Value: StringVal(val)})
}

func (r *Runner) setVarInternal(name string, vr Variable) {
	if _, ok := vr.Value.(StringVal); ok {
		if r.opts[optAllExport] {
			vr.Exported = true
		}
	} else {
		vr.Exported = false
	}
	if vr.Local {
		if r.funcVars == nil {
			r.funcVars = make(map[string]Variable)
		}
		r.funcVars[name] = vr
	} else {
		r.Vars[name] = vr
	}
	if name == "IFS" {
		r.ifsUpdated()
	}
}

func (r *Runner) setVar(ctx context.Context, name string, index syntax.ArithmExpr, vr Variable) {
	cur, _ := r.lookupVar(name)
	if cur.ReadOnly {
		r.errf("%s: readonly variable\n", name)
		r.exit = 1
		return
	}
	_, isIndexArray := cur.Value.(IndexArray)
	_, isAssocArray := cur.Value.(AssocArray)

	if _, ok := vr.Value.(StringVal); ok && index == nil {
		// When assigning a string to an array, fall back to the
		// zero value for the index.
		if isIndexArray {
			index = &syntax.Word{Parts: []syntax.WordPart{
				&syntax.Lit{Value: "0"},
			}}
		} else if isAssocArray {
			index = &syntax.Word{Parts: []syntax.WordPart{
				&syntax.DblQuoted{},
			}}
		}
	}
	if index == nil {
		r.setVarInternal(name, vr)
		return
	}

	// from the syntax package, we know that val must be a string if
	// index is non-nil; nested arrays are forbidden.
	valStr := string(vr.Value.(StringVal))

	// if the existing variable is already an AssocArray, try our best
	// to convert the key to a string
	if isAssocArray {
		amap := cur.Value.(AssocArray)
		w, ok := index.(*syntax.Word)
		if !ok {
			return
		}
		k := r.loneWord(ctx, w)
		amap[k] = valStr
		cur.Value = amap
		r.setVarInternal(name, cur)
		return
	}
	var list IndexArray
	switch x := cur.Value.(type) {
	case StringVal:
		list = append(list, string(x))
	case IndexArray:
		list = x
	case AssocArray: // done above
	}
	k := r.arithm(ctx, index)
	for len(list) < k+1 {
		list = append(list, "")
	}
	list[k] = valStr
	cur.Value = list
	r.setVarInternal(name, cur)
}

func (r *Runner) setFunc(name string, body *syntax.Stmt) {
	if r.Funcs == nil {
		r.Funcs = make(map[string]*syntax.Stmt, 4)
	}
	r.Funcs[name] = body
}

func stringIndex(index syntax.ArithmExpr) bool {
	w, ok := index.(*syntax.Word)
	if !ok || len(w.Parts) != 1 {
		return false
	}
	switch w.Parts[0].(type) {
	case *syntax.DblQuoted, *syntax.SglQuoted:
		return true
	}
	return false
}

func (r *Runner) assignVal(ctx context.Context, as *syntax.Assign, valType string) VarValue {
	prev, prevOk := r.lookupVar(as.Name.Value)
	if as.Naked {
		return prev.Value
	}
	if as.Value != nil {
		s := r.loneWord(ctx, as.Value)
		if !as.Append || !prevOk {
			return StringVal(s)
		}
		switch x := prev.Value.(type) {
		case StringVal:
			return x + StringVal(s)
		case IndexArray:
			if len(x) == 0 {
				x = append(x, "")
			}
			x[0] += s
			return x
		case AssocArray:
			// TODO
		}
		return StringVal(s)
	}
	if as.Array == nil {
		return nil
	}
	elems := as.Array.Elems
	if valType == "" {
		if len(elems) == 0 || !stringIndex(elems[0].Index) {
			valType = "-a" // indexed
		} else {
			valType = "-A" // associative
		}
	}
	if valType == "-A" {
		// associative array
		amap := AssocArray(make(map[string]string, len(elems)))
		for _, elem := range elems {
			k := r.loneWord(ctx, elem.Index.(*syntax.Word))
			amap[k] = r.loneWord(ctx, elem.Value)
		}
		if !as.Append || !prevOk {
			return amap
		}
		// TODO
		return amap
	}
	// indexed array
	maxIndex := len(elems) - 1
	indexes := make([]int, len(elems))
	for i, elem := range elems {
		if elem.Index == nil {
			indexes[i] = i
			continue
		}
		k := r.arithm(ctx, elem.Index)
		indexes[i] = k
		if k > maxIndex {
			maxIndex = k
		}
	}
	strs := make([]string, maxIndex+1)
	for i, elem := range elems {
		strs[indexes[i]] = r.loneWord(ctx, elem.Value)
	}
	if !as.Append || !prevOk {
		return IndexArray(strs)
	}
	switch x := prev.Value.(type) {
	case StringVal:
		prevList := IndexArray([]string{string(x)})
		return append(prevList, strs...)
	case IndexArray:
		return append(x, strs...)
	case AssocArray:
		// TODO
	}
	return IndexArray(strs)
}

func (r *Runner) ifsUpdated() {
	runes := r.getVar("IFS")
	r.ifsJoin = ""
	if len(runes) > 0 {
		r.ifsJoin = runes[:1]
	}
	r.ifsRune = func(r rune) bool {
		for _, r2 := range runes {
			if r == r2 {
				return true
			}
		}
		return false
	}
}

func (r *Runner) namesByPrefix(prefix string) []string {
	var names []string
	r.Env.Each(func(name, value string) bool {
		if strings.HasPrefix(name, prefix) {
			names = append(names, name)
		}
		return true
	})
	for name := range r.Vars {
		if strings.HasPrefix(name, prefix) {
			names = append(names, name)
		}
	}
	return names
}
<|endoftext|>


<commit_before>package models

import (
	"database/sql"
	"errors"
	"time"
)

// ReleaseStatus is a type alias which will be used to create an enum of acceptable release status states.
type ReleaseStatus string

// ReleaseStatus pseudo-enum values
const (
	RStatusReleased ReleaseStatus = "released"
	RStatusDraft    ReleaseStatus = "draft"
)

var (
	RStatuses = []ReleaseStatus{RStatusReleased, RStatusDraft}
)

// Errors pertaining to the data in a Release or operations on Releases.
var (
	ErrInvalidReleaseStatus = errors.New("Invalid release status.")
	ErrNoSuchRelease        = errors.New("Could not find release.")
)

// Database queries for operations on Releases.
const (
	QInitTableReleases string = `create table if not exists releases (
		id int not null auto_increment,
		chapter varchar(255),
		version int,
		status varchar(255),
		checksum varchar(255),
		released_on timestamp,
		project_id int,
		foreign key(project_id) references projects(id),
		primary key(id)
);`

	QSaveRelease string = `insert into releases (
		chapter, version, status, checksum, released_on
) values (
		?, ?, ?, ?, ?
);`

	QUpdateRelease string = `update releases set
chapter = ?, version = ?, status = ?, checksum = ?, released_on = ?
where id = ?;`

	QDeleteRelease string = `delete from releases where id = ?;`

	QListReleasesDesc string = `select
id, chapter, version, status, checksum, released_on
from releases
where project_id = ?
order by released_on desc;`

	QListReleasesAsc string = `select
id, chapter, version, status, checksum, released_on
from releases
where project_id = ?
order by released_on asc;`

	QFindRelease string = `select
chapter, version, status, checksum, released_on
from releases
where id = ?;`
)

// Release contains information about a release, which there are many of under a given Project.  It contains information
// about which chapter of manga the release was created for, which version of the release of said chapter it is for, and
// the status of the release of the chapter itself, which may not be final right away.
type Release struct {
	Id         int           `json:"id"`
	Chapter    string        `json:"chapter"`
	Version    int           `json:"version"`
	Status     ReleaseStatus `json:"status"`
	Checksum   string        `json:"checksum"`
	ReleasedOn time.Time     `json:"releasedOn:`
}

// NewRelease constructs a brand new Release instance, with a default state lacking information its (future) position in
// a database.
func NewRelease(version int, chapterName string) Release {
	return Release{
		0,
		chapterName,
		version,
		RStatusDraft,
		"",
		time.Now(),
	}
}

// FindRelease attempts to lookup a release by ID.
func FindRelease(id int, db *sql.DB) (Release, error) {
	r := Release{}
	row := db.QueryRow(QFindRelease, id)
	if row == nil {
		return Release{}, ErrNoSuchRelease
	}
	err := row.Scan(&r.Chapter, &r.Version, &r.Status, &r.Checksum, &r.ReleasedOn)
	if err != nil {
		return Release{}, err
	}
	r.Id = id
	return r, nil
}

// ListReleases attempts to obtain a list of all of the releases in the database.
func ListReleases(projectId int, ordering string, db *sql.DB) ([]Release, error) {
	releases := []Release{}
	query := QListReleasesDesc
	if ordering == "oldest" {
		query = QListReleasesAsc
	}
	rows, err := db.Query(query, projectId)
	if err != nil {
		return []Release{}, err
	}
	defer rows.Close()
	for rows.Next() {
		var id, version int
		var chapter, status, checksum string
		var released time.Time
		scanErr := rows.Scan(&id, &chapter, &version, &status, &checksum, &released)
		if scanErr != nil {
			err = scanErr
		}
		releases = append(releases, Release{id, chapter, version, ReleaseStatus(status), checksum, released})
	}
	return releases, err
}

// Validate checks that the "status" of the project is one of the accepted ReleaseStatus values.
func (r *Release) Validate() error {
	for _, status := range RStatuses {
		if r.Status == status {
			return nil
		}
	}
	return ErrInvalidReleaseStatus
}

// Save inserts the release into the database and updates its Id field.
func (r *Release) Save(db *sql.DB) error {
	validErr := r.Validate()
	if validErr != nil {
		return validErr
	}
	// TODO - Where should we compute checksums?
	_, err := db.Exec(QSaveRelease, r.Chapter, r.Version, r.Status, r.Checksum, r.ReleasedOn)
	if err != nil {
		return err
	}
	row := db.QueryRow(QLastInsertID)
	if row == nil {
		return ErrCouldNotGetID
	}
	return row.Scan(&r.Id)
}

// Update modifies all of the fields of a Release in place with whatever is currently in the struct.
func (r *Release) Update(db *sql.DB) error {
	now := time.Now()
	_, err := db.Exec(QUpdateRelease, r.Chapter, r.Version, r.Status, r.Checksum, now, r.Id)
	r.ReleasedOn = now
	return err
}

// Delete removes the Release and all associated pages from the database.
func (r *Release) Delete(db *sql.DB) error {
	pages, listErr := ListPages(r.Id, db)
	var deleteErr error
	for _, page := range pages {
		dErr := page.Delete(db)
		if dErr != nil {
			deleteErr = dErr
		}
	}
	_, err := db.Exec(QDeleteRelease, r.Id)
	if err != nil {
		return err
	}
	if listErr != nil {
		return listErr
	}
	return deleteErr
}
<commit_msg>Add a ProjectID field to the Release model<commit_after>package models

import (
	"database/sql"
	"errors"
	"time"
)

// ReleaseStatus is a type alias which will be used to create an enum of acceptable release status states.
type ReleaseStatus string

// ReleaseStatus pseudo-enum values
const (
	RStatusReleased ReleaseStatus = "released"
	RStatusDraft    ReleaseStatus = "draft"
)

var (
	RStatuses = []ReleaseStatus{RStatusReleased, RStatusDraft}
)

// Errors pertaining to the data in a Release or operations on Releases.
var (
	ErrInvalidReleaseStatus = errors.New("Invalid release status.")
	ErrNoSuchRelease        = errors.New("Could not find release.")
)

// Database queries for operations on Releases.
const (
	QInitTableReleases string = `create table if not exists releases (
		id int not null auto_increment,
		chapter varchar(255),
		version int,
		status varchar(255),
		checksum varchar(255),
		released_on timestamp,
		project_id int,
		foreign key(project_id) references projects(id),
		primary key(id)
);`

	QSaveRelease string = `insert into releases (
		chapter, version, status, checksum, released_on, project_id
) values (
		?, ?, ?, ?, ?, ?
);`

	QUpdateRelease string = `update releases set
chapter = ?, version = ?, status = ?, checksum = ?, released_on = ?
where id = ?;`

	QDeleteRelease string = `delete from releases where id = ?;`

	QListReleasesDesc string = `select
id, chapter, version, status, checksum, released_on
from releases
where project_id = ?
order by released_on desc;`

	QListReleasesAsc string = `select
id, chapter, version, status, checksum, released_on
from releases
where project_id = ?
order by released_on asc;`

	QFindRelease string = `select
chapter, version, status, checksum, released_on, project_id
from releases
where id = ?;`
)

// Release contains information about a release, which there are many of under a given Project.  It contains information
// about which chapter of manga the release was created for, which version of the release of said chapter it is for, and
// the status of the release of the chapter itself, which may not be final right away.
type Release struct {
	Id         int           `json:"id"`
	Chapter    string        `json:"chapter"`
	Version    int           `json:"version"`
	Status     ReleaseStatus `json:"status"`
	Checksum   string        `json:"checksum"`
	ReleasedOn time.Time     `json:"releasedOn"`
	ProjectID  int           `json:"projectId"`
}

// NewRelease constructs a brand new Release instance, with a default state lacking information its (future) position in
// a database.
func NewRelease(version int, chapterName string) Release {
	return Release{
		0,
		chapterName,
		version,
		RStatusDraft,
		"",
		time.Now(),
		0,
	}
}

// FindRelease attempts to lookup a release by ID.
func FindRelease(id int, db *sql.DB) (Release, error) {
	r := Release{}
	row := db.QueryRow(QFindRelease, id)
	if row == nil {
		return Release{}, ErrNoSuchRelease
	}
	err := row.Scan(&r.Chapter, &r.Version, &r.Status, &r.Checksum, &r.ReleasedOn, &r.ProjectID)
	if err != nil {
		return Release{}, err
	}
	r.Id = id
	return r, nil
}

// ListReleases attempts to obtain a list of all of the releases in the database.
func ListReleases(projectId int, ordering string, db *sql.DB) ([]Release, error) {
	releases := []Release{}
	query := QListReleasesDesc
	if ordering == "oldest" {
		query = QListReleasesAsc
	}
	rows, err := db.Query(query, projectId)
	if err != nil {
		return []Release{}, err
	}
	defer rows.Close()
	for rows.Next() {
		var id, version, projectId int
		var chapter, status, checksum string
		var released time.Time
		scanErr := rows.Scan(&id, &chapter, &version, &status, &checksum, &released, &projectId)
		if scanErr != nil {
			err = scanErr
		}
		releases = append(releases, Release{
			id,
			chapter,
			version,
			ReleaseStatus(status),
			checksum,
			released,
			projectId,
		})
	}
	return releases, err
}

// Validate checks that the "status" of the project is one of the accepted ReleaseStatus values.
func (r *Release) Validate() error {
	for _, status := range RStatuses {
		if r.Status == status {
			return nil
		}
	}
	return ErrInvalidReleaseStatus
}

// Save inserts the release into the database and updates its Id field.
func (r *Release) Save(db *sql.DB) error {
	validErr := r.Validate()
	if validErr != nil {
		return validErr
	}
	// TODO - Where should we compute checksums?
	_, err := db.Exec(QSaveRelease, r.Chapter, r.Version, r.Status, r.Checksum, r.ReleasedOn, r.ProjectID)
	if err != nil {
		return err
	}
	row := db.QueryRow(QLastInsertID)
	if row == nil {
		return ErrCouldNotGetID
	}
	return row.Scan(&r.Id)
}

// Update modifies all of the fields of a Release in place with whatever is currently in the struct.
func (r *Release) Update(db *sql.DB) error {
	now := time.Now()
	_, err := db.Exec(QUpdateRelease, r.Chapter, r.Version, r.Status, r.Checksum, now, r.Id)
	r.ReleasedOn = now
	return err
}

// Delete removes the Release and all associated pages from the database.
func (r *Release) Delete(db *sql.DB) error {
	pages, listErr := ListPages(r.Id, db)
	var deleteErr error
	for _, page := range pages {
		dErr := page.Delete(db)
		if dErr != nil {
			deleteErr = dErr
		}
	}
	_, err := db.Exec(QDeleteRelease, r.Id)
	if err != nil {
		return err
	}
	if listErr != nil {
		return listErr
	}
	return deleteErr
}
<|endoftext|>


<commit_before>package gorm

import (
	"fmt"
	"reflect"
	"strings"
	"time"
)

type postgres struct {
	commonDialect
}

func init() {
	RegisterDialect("postgres", &postgres{})
}

func (postgres) GetName() string {
	return "postgres"
}

func (postgres) BindVar(i int) string {
	return fmt.Sprintf("$%v", i)
}

func (s *postgres) DataTypeOf(field *StructField) string {
	var dataValue, sqlType, size, additionalType = ParseFieldStructForDialect(field, s)

	if sqlType == "" {
		switch dataValue.Kind() {
		case reflect.Bool:
			sqlType = "boolean"
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr:
			if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok || field.IsPrimaryKey {
				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
				sqlType = "serial"
			} else {
				sqlType = "integer"
			}
		case reflect.Int64, reflect.Uint64:
			if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok || field.IsPrimaryKey {
				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
				sqlType = "bigserial"
			} else {
				sqlType = "bigint"
			}
		case reflect.Float32, reflect.Float64:
			sqlType = "numeric"
		case reflect.String:
			if _, ok := field.TagSettings["SIZE"]; !ok {
				size = 0 // if SIZE haven't been set, use `text` as the default type, as there are no performance different
			}

			if size > 0 && size < 65532 {
				sqlType = fmt.Sprintf("varchar(%d)", size)
			} else {
				sqlType = "text"
			}
		case reflect.Struct:
			if _, ok := dataValue.Interface().(time.Time); ok {
				sqlType = "timestamp with time zone"
			}
		case reflect.Map:
			if dataValue.Type().Name() == "Hstore" {
				sqlType = "hstore"
			}
		default:
			if IsByteArrayOrSlice(dataValue) {
				sqlType = "bytea"
			} else if isUUID(dataValue) {
				sqlType = "uuid"
			}
		}
	}

	if sqlType == "" {
		panic(fmt.Sprintf("invalid sql type %s (%s) for postgres", dataValue.Type().Name(), dataValue.Kind().String()))
	}

	if strings.TrimSpace(additionalType) == "" {
		return sqlType
	}
	return fmt.Sprintf("%v %v", sqlType, additionalType)
}

func (s postgres) HasIndex(tableName string, indexName string) bool {
	var count int
	s.db.QueryRow("SELECT count(*) FROM pg_indexes WHERE tablename = $1 AND indexname = $2", tableName, indexName).Scan(&count)
	return count > 0
}

func (s postgres) HasForeignKey(tableName string, foreignKeyName string) bool {
	var count int
	s.db.QueryRow("SELECT count(con.conname) FROM pg_constraint con WHERE $1::regclass::oid = con.conrelid AND con.conname = $2 AND con.contype='f'", tableName, foreignKeyName).Scan(&count)
	return count > 0
}

func (s postgres) HasTable(tableName string) bool {
	var count int
	s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.tables WHERE table_name = $1 AND table_type = 'BASE TABLE'", tableName).Scan(&count)
	return count > 0
}

func (s postgres) HasColumn(tableName string, columnName string) bool {
	var count int
	s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.columns WHERE table_name = $1 AND column_name = $2", tableName, columnName).Scan(&count)
	return count > 0
}

func (s postgres) CurrentDatabase() (name string) {
	s.db.QueryRow("SELECT CURRENT_DATABASE()").Scan(&name)
	return
}

func (s postgres) LastInsertIDReturningSuffix(tableName, key string) string {
	return fmt.Sprintf("RETURNING %v.%v", tableName, key)
}

func (postgres) SupportLastInsertID() bool {
	return false
}

func isUUID(value reflect.Value) bool {
	if value.Kind() != reflect.Array || value.Type().Len() != 16 {
		return false
	}
	typename := value.Type().Name()
	lower := strings.ToLower(typename)
	return "uuid" == lower || "guid" == lower
}
<commit_msg>Changed the type of uint32 from integer to bigint in postgres (#1536)<commit_after>package gorm

import (
	"fmt"
	"reflect"
	"strings"
	"time"
)

type postgres struct {
	commonDialect
}

func init() {
	RegisterDialect("postgres", &postgres{})
}

func (postgres) GetName() string {
	return "postgres"
}

func (postgres) BindVar(i int) string {
	return fmt.Sprintf("$%v", i)
}

func (s *postgres) DataTypeOf(field *StructField) string {
	var dataValue, sqlType, size, additionalType = ParseFieldStructForDialect(field, s)

	if sqlType == "" {
		switch dataValue.Kind() {
		case reflect.Bool:
			sqlType = "boolean"
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uintptr:
			if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok || field.IsPrimaryKey {
				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
				sqlType = "serial"
			} else {
				sqlType = "integer"
			}
		case reflect.Int64, reflect.Uint32, reflect.Uint64:
			if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok || field.IsPrimaryKey {
				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
				sqlType = "bigserial"
			} else {
				sqlType = "bigint"
			}
		case reflect.Float32, reflect.Float64:
			sqlType = "numeric"
		case reflect.String:
			if _, ok := field.TagSettings["SIZE"]; !ok {
				size = 0 // if SIZE haven't been set, use `text` as the default type, as there are no performance different
			}

			if size > 0 && size < 65532 {
				sqlType = fmt.Sprintf("varchar(%d)", size)
			} else {
				sqlType = "text"
			}
		case reflect.Struct:
			if _, ok := dataValue.Interface().(time.Time); ok {
				sqlType = "timestamp with time zone"
			}
		case reflect.Map:
			if dataValue.Type().Name() == "Hstore" {
				sqlType = "hstore"
			}
		default:
			if IsByteArrayOrSlice(dataValue) {
				sqlType = "bytea"
			} else if isUUID(dataValue) {
				sqlType = "uuid"
			}
		}
	}

	if sqlType == "" {
		panic(fmt.Sprintf("invalid sql type %s (%s) for postgres", dataValue.Type().Name(), dataValue.Kind().String()))
	}

	if strings.TrimSpace(additionalType) == "" {
		return sqlType
	}
	return fmt.Sprintf("%v %v", sqlType, additionalType)
}

func (s postgres) HasIndex(tableName string, indexName string) bool {
	var count int
	s.db.QueryRow("SELECT count(*) FROM pg_indexes WHERE tablename = $1 AND indexname = $2", tableName, indexName).Scan(&count)
	return count > 0
}

func (s postgres) HasForeignKey(tableName string, foreignKeyName string) bool {
	var count int
	s.db.QueryRow("SELECT count(con.conname) FROM pg_constraint con WHERE $1::regclass::oid = con.conrelid AND con.conname = $2 AND con.contype='f'", tableName, foreignKeyName).Scan(&count)
	return count > 0
}

func (s postgres) HasTable(tableName string) bool {
	var count int
	s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.tables WHERE table_name = $1 AND table_type = 'BASE TABLE'", tableName).Scan(&count)
	return count > 0
}

func (s postgres) HasColumn(tableName string, columnName string) bool {
	var count int
	s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.columns WHERE table_name = $1 AND column_name = $2", tableName, columnName).Scan(&count)
	return count > 0
}

func (s postgres) CurrentDatabase() (name string) {
	s.db.QueryRow("SELECT CURRENT_DATABASE()").Scan(&name)
	return
}

func (s postgres) LastInsertIDReturningSuffix(tableName, key string) string {
	return fmt.Sprintf("RETURNING %v.%v", tableName, key)
}

func (postgres) SupportLastInsertID() bool {
	return false
}

func isUUID(value reflect.Value) bool {
	if value.Kind() != reflect.Array || value.Type().Len() != 16 {
		return false
	}
	typename := value.Type().Name()
	lower := strings.ToLower(typename)
	return "uuid" == lower || "guid" == lower
}
<|endoftext|>


<commit_before>// Copyright 2015 Geofrey Ernest a.k.a gernest, All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package filters
<commit_msg>Fix clearance<commit_after>// Copyright 2015 Geofrey Ernest a.k.a gernest, All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package filters

import (
	"github.com/gernest/lora/utils/logs"

	"github.com/astaxie/beego"
	"github.com/astaxie/beego/context"
)

var logThis = logs.NewLoraLog()

type ResourceClearance interface {
	Clear()
}

type ClearanceObject interface {
	ClearanceLevel() int
}

type BaseClearance struct {
	Ctx     *context.Context
	Objects []*baseClearanceObject
}
type baseClearanceObject struct {
	object ClearanceObject
	level  int
	pos    int
	route  string
}

func (o *baseClearanceObject) Clear() {
	beego.InsertFilter(o.route, o.pos, func(ctx *context.Context) {
		if o.object.ClearanceLevel() < o.level {
			logThis.Info("No Permission")
		}
		logThis.Info("Permitted")
	})
}

func (b *BaseClearance) Register(o ClearanceObject, level int, route string) {
	base := &baseClearanceObject{
		object: o,
		level:  level,
		pos:    beego.BeforeRouter,
		route:  route,
	}
	objects := append(b.Objects, base)
	b.Objects = objects
}

func (b *BaseClearance) ClearUp() {
	for _, ob := range b.Objects {
		ob.Clear()
	}
}
<|endoftext|>


<commit_before>package main

import (
    "github.com/rlmcpherson/s3/s3util"
    "os"
    "io"
    "fmt"
    "strings"
    "github.com/jessevdk/go-flags"
    "net/http"
    "log"

)

func main() {

    // Parse flags
    args, err := flags.Parse(&opts)
    fmt.Printf( strings.Join(args, " "))

    if err != nil {
        os.Exit(1)

    }
    s3util.DefaultConfig.AccessKey = os.Getenv("S3_ACCESS_KEY")
    s3util.DefaultConfig.SecretKey = os.Getenv("S3_SECRET_KEY")

    if opts.Down && !opts.Up{
        err := download(opts.Url)
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
        }
    }    else if opts.Up{
        err := upload(opts.Url, opts.Header)
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
        }

    } else{
        log.Fatal("specify direction of transfer: up or down")
    }

}

var opts struct {

    //AccessKey string `short:"k" long:"accesskey" description:"AWS Access Key" required:"true"`
    //SecretKey string `short:"s" long:"secretkey" description:"AWS Secret Key" required:"true"`
    Up bool `long:"up" description:"Upload to S3"`
    Down bool `long:"down" description:"Download from S3"`
    FilePath string `short:"f" long:"file_path" description:"canonical path to file" required:"true"`
    Url string `short:"u" long:"url" description:"Url of S3 object" required:"true"`
    Header http.Header `short:"h" long:"headers" description:"HTTP headers"`

}

//func open(opts struct) (io.ReadCloser, error){
//    return os.Open(opts.FilePath)
//}

func upload(url string, header http.Header) (error) {
    r, err := os.Open(opts.FilePath)
    if err != nil{
        return err
    }
    w, err := s3util.Create(url, header, nil)
    if err != nil {
        return err
    }
    if err := fileCopyClose(w, r); err != nil {return err}
    return nil
}

func download(url string) (error){
    r, err := s3util.Open(opts.Url, nil)
    if err != nil{
        return err
    }
    w, err := os.Create(opts.FilePath)
    if err != nil{
        return err
    }
    if err := fileCopyClose(w, r); err != nil {return err}
    return nil
}

func fileCopyClose(w io.WriteCloser, r io.ReadCloser) (error){
    if _, err := io.Copy(w,r); err != nil {return err}
    if err := w.Close() ; err != nil {return err }
return nil
}<commit_msg>"Md5 hash check partially implemented."<commit_after>package main

import (
    "github.com/rlmcpherson/s3/s3util"
    "os"
    "io"
    "fmt"
    "strings"
    "github.com/jessevdk/go-flags"
    "net/http"
    "log"
    "crypto/md5"

)

func main() {

    // Parse flags
    args, err := flags.Parse(&opts)
    fmt.Printf( strings.Join(args, " "))

    if err != nil {
        os.Exit(1)

    }
    s3util.DefaultConfig.AccessKey = os.Getenv("S3_ACCESS_KEY")
    s3util.DefaultConfig.SecretKey = os.Getenv("S3_SECRET_KEY")

    if opts.Down && !opts.Up{
        err := download(opts.Url)
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
        }
    }    else if opts.Up{
        err := upload(opts.Url, opts.Header, opts.Check)
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
        }

    } else{
        log.Fatal("specify direction of transfer: up or down")
    }

}

var opts struct {

    //AccessKey string `short:"k" long:"accesskey" description:"AWS Access Key" required:"true"`
    //SecretKey string `short:"s" long:"secretkey" description:"AWS Secret Key" required:"true"`
    Up bool `long:"up" description:"Upload to S3"`
    Down bool `long:"down" description:"Download from S3"`
    FilePath string `short:"f" long:"file_path" description:"canonical path to file" required:"true"`
    Url string `short:"u" long:"url" description:"Url of S3 object" required:"true"`
    Header http.Header `short:"h" long:"headers" description:"HTTP headers"`
    Check bool `short:"c" long:"checksum" description:"Verify integrity with  md5 checksum"`

}

func upload(url string, header http.Header, check bool) (error) {
    r, err := os.Open(opts.FilePath)
    if err != nil{
        return err
    }
    if (check){
        content_checksum, err := checksum(r)
        if err != nil {
            return err
        }
        header.Add("x-amz-meta-checksum", content_checksum)

    }
    w, err := s3util.Create(url, header, nil)
    if err != nil {
        return err
    }
    if err := fileCopyClose(w, r); err != nil {return err}
    return nil
}

func download(url string) (error){
    r, err := s3util.Open(opts.Url, nil)
    if err != nil{
        return err
    }
    w, err := os.Create(opts.FilePath)
    if err != nil{
        return err
    }
    if err := fileCopyClose(w, r); err != nil {return err}
    return nil
}

func fileCopyClose(w io.WriteCloser, r io.ReadCloser) (error){
    if _, err := io.Copy(w,r); err != nil {return err}
    if err := w.Close() ; err != nil {return err }
return nil
}

func checksum(r io.Reader)(string, error){
    h:= md5.New()
    io.Copy(h, r)
 return fmt.Sprintf("%x", h.Sum(nil)), nil
//return URLEncoding.EncodeToString(h.Sum(nil)), nil
}<|endoftext|>


<commit_before>package main

import (
	"os"
	"os/user"
	"testing"

	. "github.com/onsi/ginkgo"
	"github.com/stretchr/testify/assert"
)

func TestBooks(t *testing.T) {
	RunSpecs(t, "Init")
}

var _ = Describe("Init", func() {

	It("Creates an init task with defaults", func() {

		usr, _ := user.Current()
		wd, _ := os.Getwd()

		init, err := NewInitTask([]string{"test/path"})
		initTask := init.(*InitTask)

		assert.Nil(GinkgoT(), err)
		assert.Equal(GinkgoT(), initTask.ImportPath, "test/path")
		assert.Equal(GinkgoT(), initTask.ProjectPath, wd)
		assert.Equal(GinkgoT(), initTask.ProjectName, "goenv")
		assert.Equal(GinkgoT(), initTask.GoPath, usr.HomeDir+"/.goenv/goenv")
	})

	It("Creates an init task with arguments", func() {

		init, err := NewInitTask([]string{
			"-n",
			"name",
			"-g",
			"gopath",
			"-s",
			"activate",
			"-p",
			"path",
			"test/path",
		})

		initTask := init.(*InitTask)

		assert.Nil(GinkgoT(), err)
		assert.Equal(GinkgoT(), initTask.ImportPath, "test/path")
		assert.Equal(GinkgoT(), initTask.ProjectPath, "path")
		assert.Equal(GinkgoT(), initTask.ProjectName, "name")
		assert.Equal(GinkgoT(), initTask.GoPath, "gopath")
	})

	It("Returns an error if no import path is given", func() {

		_, err := NewInitTask([]string{"-n", "name"})

		assert.NotNil(GinkgoT(), err)
		assert.Contains(GinkgoT(), err.Error(), "import")
	})

})
<commit_msg>more tests<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/user"
	"path/filepath"
	"testing"

	. "github.com/onsi/ginkgo"
	"github.com/stretchr/testify/assert"
)

func TestBooks(t *testing.T) {
	RunSpecs(t, "Init")
}

var _ = Describe("Init", func() {

	It("Creates an init task with defaults", func() {

		usr, _ := user.Current()
		wd, _ := os.Getwd()

		init, err := NewInitTask([]string{"test/path"})
		initTask := init.(*InitTask)

		assert.Nil(GinkgoT(), err)
		assert.Equal(GinkgoT(), initTask.ImportPath, "test/path")
		assert.Equal(GinkgoT(), initTask.ProjectPath, wd)
		assert.Equal(GinkgoT(), initTask.ProjectName, "goenv")
		assert.Equal(GinkgoT(), initTask.GoPath, usr.HomeDir+"/.goenv/goenv")
	})

	It("Creates an init task with arguments", func() {

		init, err := NewInitTask([]string{
			"-n",
			"name",
			"-g",
			"gopath",
			"-s",
			"activate",
			"-p",
			"path",
			"test/path",
		})

		initTask := init.(*InitTask)

		assert.Nil(GinkgoT(), err)
		assert.Equal(GinkgoT(), initTask.ImportPath, "test/path")
		assert.Equal(GinkgoT(), initTask.ProjectPath, "path")
		assert.Equal(GinkgoT(), initTask.ProjectName, "name")
		assert.Equal(GinkgoT(), initTask.GoPath, "gopath")
	})

	It("Returns an error if no import path is given", func() {

		_, err := NewInitTask([]string{"-n", "name"})

		assert.NotNil(GinkgoT(), err)
		assert.Contains(GinkgoT(), err.Error(), "import")
	})

	It("Generates an activate script with the specified options", func() {

		wd, _ := os.Getwd()
		script := filepath.Join(wd, "temp")

		task := &InitTask{
			GoPath:      "go",
			ImportPath:  "import/path",
			ProjectName: "name",
			ProjectPath: "path",
			ScriptPath:  script,
		}

		task.Run()

		bytes, _ := ioutil.ReadFile(script)
		text := string(bytes)

		assert.Contains(GinkgoT(), text, "export GOENV=name")
		assert.Contains(GinkgoT(), text, "export GOPATH=go")
		assert.Contains(GinkgoT(), text, "mkdir -p $(dirname $GOPATH/src/import/path")
		assert.Contains(GinkgoT(), text, "ln -s path $GOPATH/src/import/path")

		err := os.Remove(script)

		fmt.Println(err)
	})
})
<|endoftext|>


<commit_before>package echo

type (
	Host struct {
		head   Handler
		group  *Group
		groups map[string]*Group
		Router *Router
	}
	TypeHost struct {
		prefix string
		router *Router
		echo   *Echo
	}
)

func (t TypeHost) URI(handler interface{}, params ...interface{}) string {
	if t.router == nil || t.echo == nil {
		return ``
	}
	return t.prefix + t.echo.URI(handler, params...)
}

func (h *Host) Host(args ...interface{}) (r TypeHost) {
	if h.group == nil || h.group.host == nil {
		return
	}
	r.echo = h.group.echo
	r.router = h.Router
	if len(args) != 1 {
		r.prefix = h.group.host.Format(args...)
		return
	}
	switch v := args[0].(type) {
	case map[string]interface{}:
		r.prefix = h.group.host.FormatMap(v)
	case H:
		r.prefix = h.group.host.FormatMap(v)
	default:
		r.prefix = h.group.host.Format(args...)
	}
	return
}
<commit_msg>update<commit_after>package echo

type (
	Host struct {
		head   Handler
		group  *Group
		groups map[string]*Group
		Router *Router
	}
	TypeHost struct {
		prefix string
		router *Router
		echo   *Echo
	}
)

func (t TypeHost) URI(handler interface{}, params ...interface{}) string {
	if t.router == nil || t.echo == nil {
		return ``
	}
	return t.prefix + t.echo.URI(handler, params...)
}

func (t TypeHost) String() string {
	return t.prefix
}

func (h *Host) Host(args ...interface{}) (r TypeHost) {
	if h.group == nil || h.group.host == nil {
		return
	}
	r.echo = h.group.echo
	r.router = h.Router
	if len(args) != 1 {
		r.prefix = h.group.host.Format(args...)
		return
	}
	switch v := args[0].(type) {
	case map[string]interface{}:
		r.prefix = h.group.host.FormatMap(v)
	case H:
		r.prefix = h.group.host.FormatMap(v)
	default:
		r.prefix = h.group.host.Format(args...)
	}
	return
}
<|endoftext|>


<commit_before>// Copyright 2012 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 runtime_test

import (
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"testing"
	"text/template"
)

// testEnv excludes GODEBUG from the environment
// to prevent its output from breaking tests that
// are trying to parse other command output.
func testEnv(cmd *exec.Cmd) *exec.Cmd {
	if cmd.Env != nil {
		panic("environment already set")
	}
	for _, env := range os.Environ() {
		if strings.HasPrefix(env, "GODEBUG=") {
			continue
		}
		cmd.Env = append(cmd.Env, env)
	}
	return cmd
}

func executeTest(t *testing.T, templ string, data interface{}) string {
	switch runtime.GOOS {
	case "android", "nacl":
		t.Skipf("skipping on %s", runtime.GOOS)
	}

	checkStaleRuntime(t)

	st := template.Must(template.New("crashSource").Parse(templ))

	dir, err := ioutil.TempDir("", "go-build")
	if err != nil {
		t.Fatalf("failed to create temp directory: %v", err)
	}
	defer os.RemoveAll(dir)

	src := filepath.Join(dir, "main.go")
	f, err := os.Create(src)
	if err != nil {
		t.Fatalf("failed to create file: %v", err)
	}
	err = st.Execute(f, data)
	if err != nil {
		f.Close()
		t.Fatalf("failed to execute template: %v", err)
	}
	if err := f.Close(); err != nil {
		t.Fatalf("failed to close file: %v", err)
	}

	got, _ := testEnv(exec.Command("go", "run", src)).CombinedOutput()
	return string(got)
}

func checkStaleRuntime(t *testing.T) {
	// 'go run' uses the installed copy of runtime.a, which may be out of date.
	out, err := testEnv(exec.Command("go", "list", "-f", "{{.Stale}}", "runtime")).CombinedOutput()
	if err != nil {
		t.Fatalf("failed to execute 'go list': %v\n%v", err, string(out))
	}
	if string(out) != "false\n" {
		t.Fatalf("Stale runtime.a. Run 'go install runtime'.")
	}
}

func testCrashHandler(t *testing.T, cgo bool) {
	type crashTest struct {
		Cgo bool
	}
	output := executeTest(t, crashSource, &crashTest{Cgo: cgo})
	want := "main: recovered done\nnew-thread: recovered done\nsecond-new-thread: recovered done\nmain-again: recovered done\n"
	if output != want {
		t.Fatalf("output:\n%s\n\nwanted:\n%s", output, want)
	}
}

func TestCrashHandler(t *testing.T) {
	testCrashHandler(t, false)
}

func testDeadlock(t *testing.T, source string) {
	output := executeTest(t, source, nil)
	want := "fatal error: all goroutines are asleep - deadlock!\n"
	if !strings.HasPrefix(output, want) {
		t.Fatalf("output does not start with %q:\n%s", want, output)
	}
}

func TestSimpleDeadlock(t *testing.T) {
	testDeadlock(t, simpleDeadlockSource)
}

func TestInitDeadlock(t *testing.T) {
	testDeadlock(t, initDeadlockSource)
}

func TestLockedDeadlock(t *testing.T) {
	testDeadlock(t, lockedDeadlockSource)
}

func TestLockedDeadlock2(t *testing.T) {
	testDeadlock(t, lockedDeadlockSource2)
}

func TestGoexitDeadlock(t *testing.T) {
	output := executeTest(t, goexitDeadlockSource, nil)
	want := "no goroutines (main called runtime.Goexit) - deadlock!"
	if !strings.Contains(output, want) {
		t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
	}
}

func TestStackOverflow(t *testing.T) {
	output := executeTest(t, stackOverflowSource, nil)
	want := "runtime: goroutine stack exceeds 4194304-byte limit\nfatal error: stack overflow"
	if !strings.HasPrefix(output, want) {
		t.Fatalf("output does not start with %q:\n%s", want, output)
	}
}

func TestThreadExhaustion(t *testing.T) {
	output := executeTest(t, threadExhaustionSource, nil)
	want := "runtime: program exceeds 10-thread limit\nfatal error: thread exhaustion"
	if !strings.HasPrefix(output, want) {
		t.Fatalf("output does not start with %q:\n%s", want, output)
	}
}

func TestRecursivePanic(t *testing.T) {
	output := executeTest(t, recursivePanicSource, nil)
	want := `wrap: bad
panic: again

`
	if !strings.HasPrefix(output, want) {
		t.Fatalf("output does not start with %q:\n%s", want, output)
	}

}

func TestGoexitCrash(t *testing.T) {
	output := executeTest(t, goexitExitSource, nil)
	want := "no goroutines (main called runtime.Goexit) - deadlock!"
	if !strings.Contains(output, want) {
		t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
	}
}

func TestGoNil(t *testing.T) {
	output := executeTest(t, goNilSource, nil)
	want := "go of nil func value"
	if !strings.Contains(output, want) {
		t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
	}
}

func TestMainGoroutineId(t *testing.T) {
	output := executeTest(t, mainGoroutineIdSource, nil)
	want := "panic: test\n\ngoroutine 1 [running]:\n"
	if !strings.HasPrefix(output, want) {
		t.Fatalf("output does not start with %q:\n%s", want, output)
	}
}

func TestBreakpoint(t *testing.T) {
	output := executeTest(t, breakpointSource, nil)
	want := "runtime.Breakpoint()"
	if !strings.Contains(output, want) {
		t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
	}
}

const crashSource = `
package main

import (
	"fmt"
	"runtime"
)

{{if .Cgo}}
import "C"
{{end}}

func test(name string) {
	defer func() {
		if x := recover(); x != nil {
			fmt.Printf(" recovered")
		}
		fmt.Printf(" done\n")
	}()
	fmt.Printf("%s:", name)
	var s *string
	_ = *s
	fmt.Print("SHOULD NOT BE HERE")
}

func testInNewThread(name string) {
	c := make(chan bool)
	go func() {
		runtime.LockOSThread()
		test(name)
		c <- true
	}()
	<-c
}

func main() {
	runtime.LockOSThread()
	test("main")
	testInNewThread("new-thread")
	testInNewThread("second-new-thread")
	test("main-again")
}
`

const simpleDeadlockSource = `
package main
func main() {
	select {}
}
`

const initDeadlockSource = `
package main
func init() {
	select {}
}
func main() {
}
`

const lockedDeadlockSource = `
package main
import "runtime"
func main() {
	runtime.LockOSThread()
	select {}
}
`

const lockedDeadlockSource2 = `
package main
import (
	"runtime"
	"time"
)
func main() {
	go func() {
		runtime.LockOSThread()
		select {}
	}()
	time.Sleep(time.Millisecond)
	select {}
}
`

const goexitDeadlockSource = `
package main
import (
      "runtime"
)

func F() {
      for i := 0; i < 10; i++ {
      }
}

func main() {
      go F()
      go F()
      runtime.Goexit()
}
`

const stackOverflowSource = `
package main

import "runtime/debug"

func main() {
	debug.SetMaxStack(4<<20)
	f(make([]byte, 10))
}

func f(x []byte) byte {
	var buf [64<<10]byte
	return x[0] + f(buf[:])
}
`

const threadExhaustionSource = `
package main

import (
	"runtime"
	"runtime/debug"
)

func main() {
	debug.SetMaxThreads(10)
	c := make(chan int)
	for i := 0; i < 100; i++ {
		go func() {
			runtime.LockOSThread()
			c <- 0
			select{}
		}()
		<-c
	}
}
`

const recursivePanicSource = `
package main

import (
	"fmt"
)

func main() {
	func() {
		defer func() {
			fmt.Println(recover())
		}()
		var x [8192]byte
		func(x [8192]byte) {
			defer func() {
				if err := recover(); err != nil {
					panic("wrap: " + err.(string))
				}
			}()
			panic("bad")
		}(x)
	}()
	panic("again")
}
`

const goexitExitSource = `
package main

import (
	"runtime"
	"time"
)

func main() {
	go func() {
		time.Sleep(time.Millisecond)
	}()
	i := 0
	runtime.SetFinalizer(&i, func(p *int) {})
	runtime.GC()
	runtime.Goexit()
}
`

const goNilSource = `
package main

func main() {
	defer func() {
		recover()
	}()
	var f func()
	go f()
	select{}
}
`

const mainGoroutineIdSource = `
package main
func main() {
	panic("test")
}
`

const breakpointSource = `
package main
import "runtime"
func main() {
	runtime.Breakpoint()
}
`
<commit_msg>runtime: test Goexit/defer iteraction.<commit_after>// Copyright 2012 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 runtime_test

import (
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"testing"
	"text/template"
)

// testEnv excludes GODEBUG from the environment
// to prevent its output from breaking tests that
// are trying to parse other command output.
func testEnv(cmd *exec.Cmd) *exec.Cmd {
	if cmd.Env != nil {
		panic("environment already set")
	}
	for _, env := range os.Environ() {
		if strings.HasPrefix(env, "GODEBUG=") {
			continue
		}
		cmd.Env = append(cmd.Env, env)
	}
	return cmd
}

func executeTest(t *testing.T, templ string, data interface{}) string {
	switch runtime.GOOS {
	case "android", "nacl":
		t.Skipf("skipping on %s", runtime.GOOS)
	}

	checkStaleRuntime(t)

	st := template.Must(template.New("crashSource").Parse(templ))

	dir, err := ioutil.TempDir("", "go-build")
	if err != nil {
		t.Fatalf("failed to create temp directory: %v", err)
	}
	defer os.RemoveAll(dir)

	src := filepath.Join(dir, "main.go")
	f, err := os.Create(src)
	if err != nil {
		t.Fatalf("failed to create file: %v", err)
	}
	err = st.Execute(f, data)
	if err != nil {
		f.Close()
		t.Fatalf("failed to execute template: %v", err)
	}
	if err := f.Close(); err != nil {
		t.Fatalf("failed to close file: %v", err)
	}

	got, _ := testEnv(exec.Command("go", "run", src)).CombinedOutput()
	return string(got)
}

func checkStaleRuntime(t *testing.T) {
	// 'go run' uses the installed copy of runtime.a, which may be out of date.
	out, err := testEnv(exec.Command("go", "list", "-f", "{{.Stale}}", "runtime")).CombinedOutput()
	if err != nil {
		t.Fatalf("failed to execute 'go list': %v\n%v", err, string(out))
	}
	if string(out) != "false\n" {
		t.Fatalf("Stale runtime.a. Run 'go install runtime'.")
	}
}

func testCrashHandler(t *testing.T, cgo bool) {
	type crashTest struct {
		Cgo bool
	}
	output := executeTest(t, crashSource, &crashTest{Cgo: cgo})
	want := "main: recovered done\nnew-thread: recovered done\nsecond-new-thread: recovered done\nmain-again: recovered done\n"
	if output != want {
		t.Fatalf("output:\n%s\n\nwanted:\n%s", output, want)
	}
}

func TestCrashHandler(t *testing.T) {
	testCrashHandler(t, false)
}

func testDeadlock(t *testing.T, source string) {
	output := executeTest(t, source, nil)
	want := "fatal error: all goroutines are asleep - deadlock!\n"
	if !strings.HasPrefix(output, want) {
		t.Fatalf("output does not start with %q:\n%s", want, output)
	}
}

func TestSimpleDeadlock(t *testing.T) {
	testDeadlock(t, simpleDeadlockSource)
}

func TestInitDeadlock(t *testing.T) {
	testDeadlock(t, initDeadlockSource)
}

func TestLockedDeadlock(t *testing.T) {
	testDeadlock(t, lockedDeadlockSource)
}

func TestLockedDeadlock2(t *testing.T) {
	testDeadlock(t, lockedDeadlockSource2)
}

func TestGoexitDeadlock(t *testing.T) {
	output := executeTest(t, goexitDeadlockSource, nil)
	want := "no goroutines (main called runtime.Goexit) - deadlock!"
	if !strings.Contains(output, want) {
		t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
	}
}

func TestStackOverflow(t *testing.T) {
	output := executeTest(t, stackOverflowSource, nil)
	want := "runtime: goroutine stack exceeds 4194304-byte limit\nfatal error: stack overflow"
	if !strings.HasPrefix(output, want) {
		t.Fatalf("output does not start with %q:\n%s", want, output)
	}
}

func TestThreadExhaustion(t *testing.T) {
	output := executeTest(t, threadExhaustionSource, nil)
	want := "runtime: program exceeds 10-thread limit\nfatal error: thread exhaustion"
	if !strings.HasPrefix(output, want) {
		t.Fatalf("output does not start with %q:\n%s", want, output)
	}
}

func TestRecursivePanic(t *testing.T) {
	output := executeTest(t, recursivePanicSource, nil)
	want := `wrap: bad
panic: again

`
	if !strings.HasPrefix(output, want) {
		t.Fatalf("output does not start with %q:\n%s", want, output)
	}

}

func TestGoexitCrash(t *testing.T) {
	output := executeTest(t, goexitExitSource, nil)
	want := "no goroutines (main called runtime.Goexit) - deadlock!"
	if !strings.Contains(output, want) {
		t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
	}
}

func TestGoexitDefer(t *testing.T) {
	c := make(chan struct{})
	go func() {
		defer func() {
			r := recover()
			if r != nil {
				t.Errorf("non-nil recover during Goexit")
			}
			c <- struct{}{}
		}()
		runtime.Goexit()
	}()
	// Note: if the defer fails to run, we will get a deadlock here
	<-c
}

func TestGoNil(t *testing.T) {
	output := executeTest(t, goNilSource, nil)
	want := "go of nil func value"
	if !strings.Contains(output, want) {
		t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
	}
}

func TestMainGoroutineId(t *testing.T) {
	output := executeTest(t, mainGoroutineIdSource, nil)
	want := "panic: test\n\ngoroutine 1 [running]:\n"
	if !strings.HasPrefix(output, want) {
		t.Fatalf("output does not start with %q:\n%s", want, output)
	}
}

func TestBreakpoint(t *testing.T) {
	output := executeTest(t, breakpointSource, nil)
	want := "runtime.Breakpoint()"
	if !strings.Contains(output, want) {
		t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
	}
}

const crashSource = `
package main

import (
	"fmt"
	"runtime"
)

{{if .Cgo}}
import "C"
{{end}}

func test(name string) {
	defer func() {
		if x := recover(); x != nil {
			fmt.Printf(" recovered")
		}
		fmt.Printf(" done\n")
	}()
	fmt.Printf("%s:", name)
	var s *string
	_ = *s
	fmt.Print("SHOULD NOT BE HERE")
}

func testInNewThread(name string) {
	c := make(chan bool)
	go func() {
		runtime.LockOSThread()
		test(name)
		c <- true
	}()
	<-c
}

func main() {
	runtime.LockOSThread()
	test("main")
	testInNewThread("new-thread")
	testInNewThread("second-new-thread")
	test("main-again")
}
`

const simpleDeadlockSource = `
package main
func main() {
	select {}
}
`

const initDeadlockSource = `
package main
func init() {
	select {}
}
func main() {
}
`

const lockedDeadlockSource = `
package main
import "runtime"
func main() {
	runtime.LockOSThread()
	select {}
}
`

const lockedDeadlockSource2 = `
package main
import (
	"runtime"
	"time"
)
func main() {
	go func() {
		runtime.LockOSThread()
		select {}
	}()
	time.Sleep(time.Millisecond)
	select {}
}
`

const goexitDeadlockSource = `
package main
import (
      "runtime"
)

func F() {
      for i := 0; i < 10; i++ {
      }
}

func main() {
      go F()
      go F()
      runtime.Goexit()
}
`

const stackOverflowSource = `
package main

import "runtime/debug"

func main() {
	debug.SetMaxStack(4<<20)
	f(make([]byte, 10))
}

func f(x []byte) byte {
	var buf [64<<10]byte
	return x[0] + f(buf[:])
}
`

const threadExhaustionSource = `
package main

import (
	"runtime"
	"runtime/debug"
)

func main() {
	debug.SetMaxThreads(10)
	c := make(chan int)
	for i := 0; i < 100; i++ {
		go func() {
			runtime.LockOSThread()
			c <- 0
			select{}
		}()
		<-c
	}
}
`

const recursivePanicSource = `
package main

import (
	"fmt"
)

func main() {
	func() {
		defer func() {
			fmt.Println(recover())
		}()
		var x [8192]byte
		func(x [8192]byte) {
			defer func() {
				if err := recover(); err != nil {
					panic("wrap: " + err.(string))
				}
			}()
			panic("bad")
		}(x)
	}()
	panic("again")
}
`

const goexitExitSource = `
package main

import (
	"runtime"
	"time"
)

func main() {
	go func() {
		time.Sleep(time.Millisecond)
	}()
	i := 0
	runtime.SetFinalizer(&i, func(p *int) {})
	runtime.GC()
	runtime.Goexit()
}
`

const goNilSource = `
package main

func main() {
	defer func() {
		recover()
	}()
	var f func()
	go f()
	select{}
}
`

const mainGoroutineIdSource = `
package main
func main() {
	panic("test")
}
`

const breakpointSource = `
package main
import "runtime"
func main() {
	runtime.Breakpoint()
}
`
<|endoftext|>


<commit_before>package iotool

// +build linux

import(
	"io"
	"os"
	"sync"

	"golang.org/x/sys/unix"

	"github.com/ProhtMeyhet/libgosimpleton"
	"github.com/ProhtMeyhet/libgosimpleton/abstract"
)

// this struct is used to reduce function parameters.
type FileHelper struct {
	sync.Mutex

	// the more help, the better. lots and lots and lots of help needed!
	abstract.BaseHelper
	abstract.WorkerHelper

	// os.O_RDONLY and such
	openFlags			int

	// file permissions
	permissions			os.FileMode

	// turn off checking if it's a directory. one syscall less, but the caller has to do the work.
	doNotTestForDirectory		bool

	// the read size for a buffer for io.Reader
	// FIXME -> uint
	readSize			int

	// toggled by setting stdout and stdin
	supportCli			bool
	// must not be empty!
	stdinToken			string
	stdout				io.Writer
	stdin				io.Reader
	// as a special case also support stderr
	stderr				io.Writer

	// reset all file advices
	fileAdviceNormal		bool

	// previous cached stat calls
					// map[path]os.FileInfo
	fileInfo			map[string]FileInfoInterface
//	stats				map[string]os.FileInfo
//	lstats				map[string]os.FileInfo

	// Access data only once.
	// FIXME: this is not implemented in the Linux kernel! (maybe doable via madvice?)
	fileAdviceNoReuse		bool

	// Do not expect access in the near future. Subsequent access of pages
	// in this range will succeed, but will result either in reloading of
	// the memory contents from the underlying mapped file or zero-fill-in-demand
	// pages for mappings without an underlying file.
	// Linux: Drop the file from cache. Note this is automatically done when files are unlinked.
	fileAdviceDontNeed		bool

	// Expect page references in random order
	// Linux: Sets FMODE_RANDOM on the file descriptor (fd)
	fileAdviceReadRandom		bool

	// Expect page references in sequential order
	// Linux: Doubles the size of read ahead done for file
	fileAdviceReadSequential	bool

	// Expect access in the near future
	// Linux: _synchronously_ prepopulate the buffer cache with the file
	fileAdviceWillNeed		bool
}

// fresh and shiny
func newFileHelper() *FileHelper {
	helper := &FileHelper{}
	// FIXME onE
	helper.BaseHelper.Initialise(abstract.IgnoreErrors)
	helper.WorkerHelper.Initialise()
	helper.readSize = READ_BUFFER_SIZE
	helper.fileInfo = make(map[string]FileInfoInterface)
	return helper
}

// open for read only
func ReadOnly() *FileHelper {
	helper := newFileHelper()
	return helper.ReadOnly()
}

// open for write only
func WriteOnly() *FileHelper {
	helper := newFileHelper()
	return helper.WriteOnly()
}

// open read and write
func ReadAndWrite() *FileHelper {
	helper := newFileHelper()
	return helper.ReadAndWrite()
}

// set the file advices on file descriptors (fd). ignore all errors (just like coreutils does)
func (helper *FileHelper) ApplyFileAdvice(to FileInterface) {
	if to == nil { return }

	fd := int(to.Fd())

	if helper.fileAdviceNormal {
		unix.Fadvise(fd, 0, 0, 0) // 0 == POSIX_FADV_NORMAL
		helper.fileAdviceNormal = false
		return
	}

	if helper.ShouldFileAdviceReadRandom() {
		unix.Fadvise(fd, 0, 0, 1) // 1 == POSIX_FADV_RANDOM
	}

	if helper.ShouldFileAdviceReadSequential() {
		unix.Fadvise(fd, 0, 0, 2) // 2 == POSIX_FADV_SEQUENTIAL
	}

	// go, as the linux kernel is immidiatly calling force_page_cache_readahead
	if helper.ShouldFileAdviceWillNeed() {
		go unix.Fadvise(fd, 0, 0, 3) // 3 == POSIX_FADV_WILLNEED
	}

	// go, as the linux kernel is immidiatly doing some work
	if helper.ShouldFileAdviceDontNeed() {
		go unix.Fadvise(fd, 0, 0, 4) // 4 == POSIX_FADV_DONTNEED
	}

	if helper.ShouldFileAdviceNoReuse() {
		unix.Fadvise(fd, 0, 0, 5) // 5 == POSIX_FADV_NOREUSE
	}
}

// resets all file advices on $to and in this helper
func (helper *FileHelper) ResetFileAdvice(to FileInterface) {
	helper.fileAdviceNormal = true
	helper.fileAdviceReadRandom = false
	helper.fileAdviceReadSequential = false
	helper.fileAdviceWillNeed = false
	helper.fileAdviceDontNeed = false
	helper.fileAdviceNoReuse = false
	helper.ApplyFileAdvice(to)
}

// copy several values from a helper
func (helper *FileHelper) Copy(from interface{}) *FileHelper {
	// FIXME
//	helper.BaseHelper.Copy(from)
//	helper.WorkerHelper.Copy(from)

	if fileHelper, ok := from.(*FileHelper); ok {
		helper.fileAdviceNormal = fileHelper.fileAdviceNormal
		helper.fileAdviceReadRandom = fileHelper.fileAdviceReadRandom
		helper.fileAdviceReadSequential = fileHelper.fileAdviceReadSequential
		helper.fileAdviceWillNeed = fileHelper.fileAdviceWillNeed
		helper.fileAdviceDontNeed = fileHelper.fileAdviceDontNeed
		helper.fileAdviceNoReuse = fileHelper.fileAdviceNoReuse

		if fileHelper.HasAppend() { helper.ToggleAppend() }
		if fileHelper.HasCreate() { helper.ToggleCreate() }
		if fileHelper.HasExclusive() { helper.ToggleExclusive() }
		if fileHelper.HasSynchronous() { helper.ToggleSynchronous() }
		if fileHelper.HasTruncate() { helper.ToggleTruncate() }

		for key := range fileHelper.fileInfo {
			if _, ok := helper.fileInfo[key]; !ok {
				helper.fileInfo[key] = fileHelper.fileInfo[key]
			}
		}
	}

	return helper
}

// get read size
func (helper *FileHelper) ReadSize() int {
	return helper.readSize
}

func (helper *FileHelper) SetReadSize(to int) *FileHelper {
	// it wasn't a very wise decision to use signed ints for lengths...
	if to > 0 {
		helper.readSize = to
	}
	return helper
}

// FIXME: correct lstat cache
func (helper *FileHelper) FileInfo(path string, lstat bool) (FileInfoInterface, error) {
	var e error
	if _, ok := helper.fileInfo[path]; !ok {
		var info os.FileInfo
		if lstat {
			info, e = os.Lstat(path); if e != nil { return nil, e }
		} else {
			info, e = os.Stat(path); if e != nil { return nil, e }
		}
		helper.Lock(); helper.fileInfo[path] = NewFileInfo(path, info); helper.Unlock()
	}

	return helper.fileInfo[path], e
}

func (helper *FileHelper) SupportCli() bool {
	return helper.supportCli
}

// toggle supportCli by setting STDIN and STDOUT in SetStdinStdout()

func (helper *FileHelper) IsStdinToken(what string) bool {
	return helper.stdinToken == what
}

func (helper *FileHelper) Stdin() io.Reader {
	return helper.stdin
}

func (helper *FileHelper) Stdout() io.Writer {
	return helper.stdout
}

func (helper *FileHelper) Stderr() io.Writer {
	return helper.stderr
}

// only support supplying both
func (helper *FileHelper) SetStdinStdout(astdinToken string, astdin io.Reader, astdout io.Writer) {
	helper.supportCli = true
	// disallow empty value
	if astdinToken != "" {
		helper.stdinToken = astdinToken
	} else {
		helper.stdinToken = STDIN_TOKEN
	}
	helper.stdin = astdin
	helper.stdout = astdout
}

func (helper *FileHelper) SetStderr(astderr io.Writer) {
	helper.stderr = astderr
}

// sets to read only and discards all other flags
func (helper *FileHelper) ReadOnly() *FileHelper {
	helper.openFlags = os.O_RDONLY
	return helper
}

// sets to write only and discards all other flags
func (helper *FileHelper) WriteOnly() *FileHelper {
	helper.openFlags = os.O_WRONLY
	return helper
}

// sets to read and write and discards all other flags
func (helper *FileHelper) ReadAndWrite() *FileHelper {
	helper.openFlags = os.O_RDWR
	return helper
}

// is append already active
func (helper *FileHelper) HasAppend() bool {
	return helper.openFlags ^ os.O_APPEND < helper.openFlags
}

// add append to flags
func (helper *FileHelper) ToggleAppend() *FileHelper {
	helper.openFlags ^= os.O_APPEND
	return helper
}

// is append already active
func (helper *FileHelper) HasCreate() bool {
	return helper.openFlags ^ os.O_CREATE < helper.openFlags
}

// add create to flags
func (helper *FileHelper) ToggleCreate() *FileHelper {
	helper.openFlags ^= os.O_CREATE
	helper.permissions = 0666
	return helper
}

// is exlusive already active
func (helper *FileHelper) HasExclusive() bool {
	return helper.openFlags ^ os.O_EXCL < helper.openFlags
}

// add exclusive to flags
func (helper *FileHelper) ToggleExclusive() *FileHelper {
	helper.openFlags ^= os.O_EXCL
	return helper
}

// is synchronized already active
func (helper *FileHelper) HasSynchronous() bool {
	return helper.openFlags ^ os.O_SYNC < helper.openFlags
}
// add sync to flags
func (helper *FileHelper) ToggleSynchronous() *FileHelper {
	helper.openFlags ^= os.O_SYNC
	return helper
}

// is truncate already active
func (helper *FileHelper) HasTruncate() bool {
	return helper.openFlags ^ os.O_TRUNC < helper.openFlags
}
// add trunc to flags
func (helper *FileHelper) ToggleTruncate() *FileHelper {
	helper.openFlags ^= os.O_TRUNC
	return helper
}

// return open flags
func (helper *FileHelper) OpenFlags() int {
	return helper.openFlags
}

// return permissions
func (helper *FileHelper) Permissions() os.FileMode {
	return helper.permissions
}

// set permissions
func (helper *FileHelper) SetPermissions(to os.FileMode) *FileHelper {
	helper.permissions = to
	return helper
}

// get if test for directory
func (helper *FileHelper) DoNotTestForDirectory() bool {
	return helper.doNotTestForDirectory
}

// please do file advice DONT_NEED
func (helper *FileHelper) ToggleFileAdviceDontNeed() *FileHelper {
	if !libgosimpleton.SET_FILE_ADVICE_DONTNEED { goto out }
	helper.fileAdviceDontNeed = !helper.fileAdviceDontNeed

out:
	return helper
}

// thats a question to be answered
func (helper *FileHelper) ShouldFileAdviceDontNeed() bool {
	return helper.fileAdviceDontNeed
}

// please do file advice SEQUENTIAL_READ
func (helper *FileHelper) ToggleFileAdviceReadSequential() *FileHelper {
	helper.fileAdviceReadSequential = !helper.fileAdviceReadSequential
	return helper
}

// thats a question to be answered
func (helper *FileHelper) ShouldFileAdviceReadSequential() bool {
	return helper.fileAdviceReadSequential
}

// please do file advice RANDOM_READ
func (helper *FileHelper) ToggleFileAdviceReadRandom() *FileHelper {
	helper.fileAdviceReadRandom = !helper.fileAdviceReadRandom
	return helper
}

// thats a question to be answered
func (helper *FileHelper) ShouldFileAdviceReadRandom() bool {
	return helper.fileAdviceReadRandom
}

// please do file advice WILLNEED
func (helper *FileHelper) ToggleFileAdviceWillNeed() *FileHelper {
	helper.fileAdviceWillNeed = !helper.fileAdviceWillNeed
	return helper
}

// thats a question to be answered
func (helper *FileHelper) ShouldFileAdviceWillNeed() bool {
	return helper.fileAdviceWillNeed
}

// please do file advice NO_REUSE
func (helper *FileHelper) ToggleFileAdviceNoReuse() *FileHelper {
	helper.fileAdviceNoReuse = !helper.fileAdviceNoReuse
	return helper
}

// thats a question to be answered
func (helper *FileHelper) ShouldFileAdviceNoReuse() bool {
	return helper.fileAdviceNoReuse
}

// @override toggle cache you should
func (helper *FileHelper) ToggleCache() {
	helper.BaseHelper.ToggleCache()
	if !helper.ShouldCache() {
		helper.ToggleFileAdviceDontNeed()
		helper.ToggleFileAdviceNoReuse()
	}
}
<commit_msg>add some documentation<commit_after>package iotool

// +build linux

import(
	"io"
	"os"
	"sync"

	"golang.org/x/sys/unix"

	"github.com/ProhtMeyhet/libgosimpleton"
	"github.com/ProhtMeyhet/libgosimpleton/abstract"
)

// this struct is used to reduce function parameters.
type FileHelper struct {
	sync.Mutex

	// the more help, the better. lots and lots and lots of help needed!
	abstract.BaseHelper
	abstract.WorkerHelper

	// os.O_RDONLY and such
	openFlags			int

	// file permissions
	permissions			os.FileMode

	// turn off checking if it's a directory. one syscall less, but the caller has to do the work.
	doNotTestForDirectory		bool

	// the read size for a buffer for io.Reader
	// FIXME -> uint
	readSize			int

	// toggled by setting stdout and stdin
	supportCli			bool
	// must not be empty!
	stdinToken			string
	stdout				io.Writer
	stdin				io.Reader
	// as a special case also support stderr
	stderr				io.Writer

	// reset all file advices
	fileAdviceNormal		bool

	// previous cached stat calls
					// map[path]os.FileInfo
	fileInfo			map[string]FileInfoInterface
//	stats				map[string]os.FileInfo
//	lstats				map[string]os.FileInfo

	// Access data only once.
	// FIXME: this is not implemented in the Linux kernel! (maybe doable via madvice?)
	fileAdviceNoReuse		bool

	// Do not expect access in the near future. Subsequent access of pages
	// in this range will succeed, but will result either in reloading of
	// the memory contents from the underlying mapped file or zero-fill-in-demand
	// pages for mappings without an underlying file.
	// Linux: Drop the file from cache. Note this is automatically done when files are unlinked.
	fileAdviceDontNeed		bool

	// Expect page references in random order
	// Linux: Sets FMODE_RANDOM on the file descriptor (fd)
	fileAdviceReadRandom		bool

	// Expect page references in sequential order
	// Linux: Doubles the size of read ahead done for file
	fileAdviceReadSequential	bool

	// Expect access in the near future
	// Linux: _synchronously_ prepopulate the buffer cache with the file
	fileAdviceWillNeed		bool
}

// fresh and shiny
func newFileHelper() *FileHelper {
	helper := &FileHelper{}
	// FIXME onE
	helper.BaseHelper.Initialise(abstract.IgnoreErrors)
	helper.WorkerHelper.Initialise()
	helper.readSize = READ_BUFFER_SIZE
	helper.fileInfo = make(map[string]FileInfoInterface)
	return helper
}

// open for read only
func ReadOnly() *FileHelper {
	helper := newFileHelper()
	return helper.ReadOnly()
}

// open for write only
func WriteOnly() *FileHelper {
	helper := newFileHelper()
	return helper.WriteOnly()
}

// open read and write
func ReadAndWrite() *FileHelper {
	helper := newFileHelper()
	return helper.ReadAndWrite()
}

// set the file advices on file descriptors (fd). ignore all errors (just like coreutils does)
func (helper *FileHelper) ApplyFileAdvice(to FileInterface) {
	if to == nil { return }

	fd := int(to.Fd())

	if helper.fileAdviceNormal {
		unix.Fadvise(fd, 0, 0, 0) // 0 == POSIX_FADV_NORMAL
		helper.fileAdviceNormal = false
		return
	}

	if helper.ShouldFileAdviceReadRandom() {
		unix.Fadvise(fd, 0, 0, 1) // 1 == POSIX_FADV_RANDOM
	}

	if helper.ShouldFileAdviceReadSequential() {
		unix.Fadvise(fd, 0, 0, 2) // 2 == POSIX_FADV_SEQUENTIAL
	}

	// go, as the linux kernel is immidiatly calling force_page_cache_readahead
	if helper.ShouldFileAdviceWillNeed() {
		go unix.Fadvise(fd, 0, 0, 3) // 3 == POSIX_FADV_WILLNEED
	}

	// go, as the linux kernel is immidiatly doing some work
	if helper.ShouldFileAdviceDontNeed() {
		go unix.Fadvise(fd, 0, 0, 4) // 4 == POSIX_FADV_DONTNEED
	}

	if helper.ShouldFileAdviceNoReuse() {
		unix.Fadvise(fd, 0, 0, 5) // 5 == POSIX_FADV_NOREUSE
	}
}

// resets all file advices on $to and in this helper
func (helper *FileHelper) ResetFileAdvice(to FileInterface) {
	helper.fileAdviceNormal = true
	helper.fileAdviceReadRandom = false
	helper.fileAdviceReadSequential = false
	helper.fileAdviceWillNeed = false
	helper.fileAdviceDontNeed = false
	helper.fileAdviceNoReuse = false
	helper.ApplyFileAdvice(to)
}

// copy several values from a helper
func (helper *FileHelper) Copy(from interface{}) *FileHelper {
	// FIXME
//	helper.BaseHelper.Copy(from)
//	helper.WorkerHelper.Copy(from)

	if fileHelper, ok := from.(*FileHelper); ok {
		helper.fileAdviceNormal = fileHelper.fileAdviceNormal
		helper.fileAdviceReadRandom = fileHelper.fileAdviceReadRandom
		helper.fileAdviceReadSequential = fileHelper.fileAdviceReadSequential
		helper.fileAdviceWillNeed = fileHelper.fileAdviceWillNeed
		helper.fileAdviceDontNeed = fileHelper.fileAdviceDontNeed
		helper.fileAdviceNoReuse = fileHelper.fileAdviceNoReuse

		if fileHelper.HasAppend() { helper.ToggleAppend() }
		if fileHelper.HasCreate() { helper.ToggleCreate() }
		if fileHelper.HasExclusive() { helper.ToggleExclusive() }
		if fileHelper.HasSynchronous() { helper.ToggleSynchronous() }
		if fileHelper.HasTruncate() { helper.ToggleTruncate() }

		for key := range fileHelper.fileInfo {
			if _, ok := helper.fileInfo[key]; !ok {
				helper.fileInfo[key] = fileHelper.fileInfo[key]
			}
		}
	}

	return helper
}

// get read size
func (helper *FileHelper) ReadSize() int {
	return helper.readSize
}

func (helper *FileHelper) SetReadSize(to int) *FileHelper {
	// it wasn't a very wise decision to use signed ints for lengths...
	if to > 0 {
		helper.readSize = to
	}
	return helper
}

// FIXME: correct lstat cache
func (helper *FileHelper) FileInfo(path string, lstat bool) (FileInfoInterface, error) {
	var e error
	if _, ok := helper.fileInfo[path]; !ok {
		var info os.FileInfo
		if lstat {
			info, e = os.Lstat(path); if e != nil { return nil, e }
		} else {
			info, e = os.Stat(path); if e != nil { return nil, e }
		}
		helper.Lock(); helper.fileInfo[path] = NewFileInfo(path, info); helper.Unlock()
	}

	return helper.fileInfo[path], e
}

// return if cli output is supported
func (helper *FileHelper) SupportCli() bool {
	return helper.supportCli
}

// toggle supportCli by setting STDIN and STDOUT in SetStdinStdout()

// return if string is equal to STDIN token (usualley "-")
func (helper *FileHelper) IsStdinToken(what string) bool {
	return helper.stdinToken == what
}

// get STDIN to use
func (helper *FileHelper) Stdin() io.Reader {
	return helper.stdin
}

// get STDOUT to use
func (helper *FileHelper) Stdout() io.Writer {
	return helper.stdout
}

// get STDERR to use
func (helper *FileHelper) Stderr() io.Writer {
	return helper.stderr
}

// set STDIN and STDOUT. only support supplying both
func (helper *FileHelper) SetStdinStdout(astdinToken string, astdin io.Reader, astdout io.Writer) {
	helper.supportCli = true
	// disallow empty value
	if astdinToken != "" {
		helper.stdinToken = astdinToken
	} else {
		helper.stdinToken = STDIN_TOKEN
	}
	helper.stdin = astdin
	helper.stdout = astdout
}

// set STDERR to a io.Writer
func (helper *FileHelper) SetStderr(astderr io.Writer) {
	helper.stderr = astderr
}

// sets to read only and discards all other flags
func (helper *FileHelper) ReadOnly() *FileHelper {
	helper.openFlags = os.O_RDONLY
	return helper
}

// sets to write only and discards all other flags
func (helper *FileHelper) WriteOnly() *FileHelper {
	helper.openFlags = os.O_WRONLY
	return helper
}

// sets to read and write and discards all other flags
func (helper *FileHelper) ReadAndWrite() *FileHelper {
	helper.openFlags = os.O_RDWR
	return helper
}

// is append already active
func (helper *FileHelper) HasAppend() bool {
	return helper.openFlags ^ os.O_APPEND < helper.openFlags
}

// add append to flags
func (helper *FileHelper) ToggleAppend() *FileHelper {
	helper.openFlags ^= os.O_APPEND
	return helper
}

// is append already active
func (helper *FileHelper) HasCreate() bool {
	return helper.openFlags ^ os.O_CREATE < helper.openFlags
}

// add create to flags
func (helper *FileHelper) ToggleCreate() *FileHelper {
	helper.openFlags ^= os.O_CREATE
	helper.permissions = 0666
	return helper
}

// is exlusive already active
func (helper *FileHelper) HasExclusive() bool {
	return helper.openFlags ^ os.O_EXCL < helper.openFlags
}

// add exclusive to flags
func (helper *FileHelper) ToggleExclusive() *FileHelper {
	helper.openFlags ^= os.O_EXCL
	return helper
}

// is synchronized already active
func (helper *FileHelper) HasSynchronous() bool {
	return helper.openFlags ^ os.O_SYNC < helper.openFlags
}
// add sync to flags
func (helper *FileHelper) ToggleSynchronous() *FileHelper {
	helper.openFlags ^= os.O_SYNC
	return helper
}

// is truncate already active
func (helper *FileHelper) HasTruncate() bool {
	return helper.openFlags ^ os.O_TRUNC < helper.openFlags
}
// add trunc to flags
func (helper *FileHelper) ToggleTruncate() *FileHelper {
	helper.openFlags ^= os.O_TRUNC
	return helper
}

// return open flags
func (helper *FileHelper) OpenFlags() int {
	return helper.openFlags
}

// return permissions
func (helper *FileHelper) Permissions() os.FileMode {
	return helper.permissions
}

// set permissions
func (helper *FileHelper) SetPermissions(to os.FileMode) *FileHelper {
	helper.permissions = to
	return helper
}

// get if test for directory
func (helper *FileHelper) DoNotTestForDirectory() bool {
	return helper.doNotTestForDirectory
}

// please do file advice DONT_NEED
func (helper *FileHelper) ToggleFileAdviceDontNeed() *FileHelper {
	if !libgosimpleton.SET_FILE_ADVICE_DONTNEED { goto out }
	helper.fileAdviceDontNeed = !helper.fileAdviceDontNeed

out:
	return helper
}

// thats a question to be answered
func (helper *FileHelper) ShouldFileAdviceDontNeed() bool {
	return helper.fileAdviceDontNeed
}

// please do file advice SEQUENTIAL_READ
func (helper *FileHelper) ToggleFileAdviceReadSequential() *FileHelper {
	helper.fileAdviceReadSequential = !helper.fileAdviceReadSequential
	return helper
}

// thats a question to be answered
func (helper *FileHelper) ShouldFileAdviceReadSequential() bool {
	return helper.fileAdviceReadSequential
}

// please do file advice RANDOM_READ
func (helper *FileHelper) ToggleFileAdviceReadRandom() *FileHelper {
	helper.fileAdviceReadRandom = !helper.fileAdviceReadRandom
	return helper
}

// thats a question to be answered
func (helper *FileHelper) ShouldFileAdviceReadRandom() bool {
	return helper.fileAdviceReadRandom
}

// please do file advice WILLNEED
func (helper *FileHelper) ToggleFileAdviceWillNeed() *FileHelper {
	helper.fileAdviceWillNeed = !helper.fileAdviceWillNeed
	return helper
}

// thats a question to be answered
func (helper *FileHelper) ShouldFileAdviceWillNeed() bool {
	return helper.fileAdviceWillNeed
}

// please do file advice NO_REUSE
func (helper *FileHelper) ToggleFileAdviceNoReuse() *FileHelper {
	helper.fileAdviceNoReuse = !helper.fileAdviceNoReuse
	return helper
}

// thats a question to be answered
func (helper *FileHelper) ShouldFileAdviceNoReuse() bool {
	return helper.fileAdviceNoReuse
}

// @override toggle cache you should
func (helper *FileHelper) ToggleCache() {
	helper.BaseHelper.ToggleCache()
	if !helper.ShouldCache() {
		helper.ToggleFileAdviceDontNeed()
		helper.ToggleFileAdviceNoReuse()
	}
}
<|endoftext|>


<commit_before>package gitmediafilters

import (
	".."
	"crypto/sha1"
	"encoding/hex"
	"io"
	"os"
)

type CleanedAsset struct {
	Size          int64
	File          *os.File
	Sha           string
	mediafilepath string
}

func Clean(reader io.Reader) (*CleanedAsset, error) {
	tmp, err := gitmedia.TempFile()
	if err != nil {
		return nil, err
	}

	sha1Hash := sha1.New()
	writer := io.MultiWriter(sha1Hash, tmp)
	written, err := io.Copy(writer, reader)

	return &CleanedAsset{written, tmp, hex.EncodeToString(sha1Hash.Sum(nil)), ""}, err
}

func (a *CleanedAsset) Close() error {
	return os.Remove(a.File.Name())
}
<commit_msg>ララララー ラララー ララ<commit_after>package gitmediafilters

import (
	".."
	"crypto/sha256"
	"encoding/hex"
	"io"
	"os"
	"strconv"
)

type CleanedAsset struct {
	Size          int64
	File          *os.File
	Sha           string
	mediafilepath string
}

func Clean(reader io.Reader) (*CleanedAsset, error) {
	tmp, err := gitmedia.TempFile()
	if err != nil {
		return nil, err
	}

	oidHash := sha256.New()
	writer := io.MultiWriter(oidHash, tmp)
	written, err := io.Copy(writer, reader)

	return &CleanedAsset{written, tmp, hex.EncodeToString(oidHash.Sum(nil)), ""}, err
}

func (a *CleanedAsset) Close() error {
	return os.Remove(a.File.Name())
}
<|endoftext|>