<commit_before>package gorethink

import (
	"fmt"
	"math"
	"reflect"
	"strconv"
	"strings"
	"sync/atomic"
	"time"

	"code.google.com/p/goprotobuf/proto"
	"github.com/dancannon/gorethink/encoding"
	p "github.com/dancannon/gorethink/ql2"
)

// Helper functions for constructing terms

// constructRootTerm is an alias for creating a new term.
func constructRootTerm(name string, termType p.Term_TermType, args []interface{}, optArgs map[string]interface{}) Term {
	return Term{
		name:     name,
		rootTerm: true,
		termType: termType,
		args:     convertTermList(args),
		optArgs:  convertTermObj(optArgs),
	}
}

// constructMethodTerm is an alias for creating a new term. Unlike constructRootTerm
// this function adds the previous expression in the tree to the argument list to
// create a method term.
func constructMethodTerm(prevVal Term, name string, termType p.Term_TermType, args []interface{}, optArgs map[string]interface{}) Term {
	args = append([]interface{}{prevVal}, args...)

	return Term{
		name:     name,
		rootTerm: false,
		termType: termType,
		args:     convertTermList(args),
		optArgs:  convertTermObj(optArgs),
	}
}

// Helper functions for creating internal RQL types

// makeArray takes a slice of terms and produces a single MAKE_ARRAY term
func makeArray(args termsList) Term {
	return Term{
		name:     "[...]",
		termType: p.Term_MAKE_ARRAY,
		args:     args,
	}
}

// makeObject takes a map of terms and produces a single MAKE_OBJECT term
func makeObject(args termsObj) Term {
	// First all evaluate all fields in the map
	temp := termsObj{}
	for k, v := range args {
		temp[k] = Expr(v)
	}

	return Term{
		name:     "{...}",
		termType: p.Term_MAKE_OBJ,
		optArgs:  temp,
	}
}

var nextVarId int64 = 0

func makeFunc(f interface{}) Term {
	value := reflect.ValueOf(f)
	valueType := value.Type()

	var argNums []interface{}
	var args []reflect.Value
	for i := 0; i < valueType.NumIn(); i++ {
		// Get a slice of the VARs to use as the function arguments
		args = append(args, reflect.ValueOf(constructRootTerm("var", p.Term_VAR, []interface{}{nextVarId}, map[string]interface{}{})))
		argNums = append(argNums, nextVarId)
		atomic.AddInt64(&nextVarId, 1)

		// make sure all input arguments are of type Term
		if valueType.In(i).String() != "gorethink.Term" {
			panic("Function argument is not of type Term")
		}
	}

	if valueType.NumOut() != 1 {
		panic("Function does not have a single return value")
	}

	body := value.Call(args)[0].Interface()
	argsArr := makeArray(convertTermList(argNums))

	return constructRootTerm("func", p.Term_FUNC, []interface{}{argsArr, body}, map[string]interface{}{})
}

func funcWrap(value interface{}) Term {
	val := Expr(value)

	if implVarScan(val) {
		return makeFunc(func(x Term) Term {
			return val
		})
	} else {
		return val
	}
}

func funcWrapArgs(args []interface{}) []interface{} {
	for i, arg := range args {
		args[i] = funcWrap(arg)
	}

	return args
}

// implVarScan recursivly checks a value to see if it contains an
// IMPLICIT_VAR term. If it does it returns true
func implVarScan(value Term) bool {
	if value.termType == p.Term_IMPLICIT_VAR {
		return true
	} else {
		for _, v := range value.args {
			if implVarScan(v) {
				return true
			}
		}

		for _, v := range value.optArgs {
			if implVarScan(v) {
				return true
			}
		}

		return false
	}
}

// Convert an opt args struct to a map.
func optArgsToMap(optArgs OptArgs) map[string]interface{} {
	data, err := encode(optArgs)

	if err == nil && data != nil {
		if m, ok := data.(map[string]interface{}); ok {
			return m
		}
	}

	return map[string]interface{}{}
}

// Convert a list into a slice of terms
func convertTermList(l []interface{}) termsList {
	terms := termsList{}
	for _, v := range l {
		terms = append(terms, Expr(v))
	}

	return terms
}

// Convert a map into a map of terms
func convertTermObj(o map[string]interface{}) termsObj {
	terms := termsObj{}
	for k, v := range o {
		terms[k] = Expr(v)
	}

	return terms
}

func mergeArgs(args ...interface{}) []interface{} {
	newArgs := []interface{}{}

	for _, arg := range args {
		switch v := arg.(type) {
		case []interface{}:
			newArgs = append(newArgs, v...)
		default:
			newArgs = append(newArgs, v)
		}
	}

	return newArgs
}

// Pseudo-type helper functions

func reqlTimeToNativeTime(timestamp float64, timezone string) (time.Time, error) {
	sec, ms := math.Modf(timestamp)

	t := time.Unix(int64(sec), int64(ms*1000*1000*1000))

	// Caclulate the timezone
	if timezone != "" {
		hours, err := strconv.Atoi(timezone[1:3])
		if err != nil {
			return time.Time{}, err
		}
		minutes, err := strconv.Atoi(timezone[4:6])
		if err != nil {
			return time.Time{}, err
		}
		tzOffset := ((hours * 60) + minutes) * 60
		if timezone[:1] == "-" {
			tzOffset = 0 - tzOffset
		}

		t = t.In(time.FixedZone(timezone, tzOffset))
	}

	return t, nil
}

func reqlGroupedDataToObj(obj map[string]interface{}) (interface{}, error) {
	if data, ok := obj["data"]; ok {
		ret := []interface{}{}
		for _, v := range data.([]interface{}) {
			v := v.([]interface{})
			ret = append(ret, map[string]interface{}{
				"group":     v[0],
				"reduction": v[1],
			})
		}
		return ret, nil
	} else {
		return nil, fmt.Errorf("pseudo-type GROUPED_DATA object %v does not have the expected field \"data\"", obj)
	}
}

// Helper functions for debugging

func allArgsToStringSlice(args termsList, optArgs termsObj) []string {
	allArgs := []string{}

	for _, v := range args {
		allArgs = append(allArgs, v.String())
	}
	for k, v := range optArgs {
		allArgs = append(allArgs, k+"="+v.String())
	}

	return allArgs
}

func argsToStringSlice(args termsList) []string {
	allArgs := []string{}

	for _, v := range args {
		allArgs = append(allArgs, v.String())
	}

	return allArgs
}

func optArgsToStringSlice(optArgs termsObj) []string {
	allArgs := []string{}

	for k, v := range optArgs {
		allArgs = append(allArgs, k+"="+v.String())
	}

	return allArgs
}

func prefixLines(s string, prefix string) (result string) {
	for _, line := range strings.Split(s, "\n") {
		result += prefix + line + "\n"
	}
	return
}

func protobufToString(p proto.Message, indentLevel int) string {
	return prefixLines(proto.MarshalTextString(p), strings.Repeat("    ", indentLevel))
}

func encode(v interface{}) (interface{}, error) {
	encoding.RegisterEncodeHook(func(v reflect.Value) (success bool, ret reflect.Value, err error) {
		if v.Type() == reflect.TypeOf(time.Time{}) {
			return true, v, nil
		} else if v.Type() == reflect.TypeOf(Term{}) {
			return true, v, nil
		} else {
			return false, v, nil
		}
	})

	return encoding.Encode(v)
}
<commit_msg>Removed funcWrap of r.Args<commit_after>package gorethink

import (
	"fmt"
	"math"
	"reflect"
	"strconv"
	"strings"
	"sync/atomic"
	"time"

	"code.google.com/p/goprotobuf/proto"
	"github.com/dancannon/gorethink/encoding"
	p "github.com/dancannon/gorethink/ql2"
)

// Helper functions for constructing terms

// constructRootTerm is an alias for creating a new term.
func constructRootTerm(name string, termType p.Term_TermType, args []interface{}, optArgs map[string]interface{}) Term {
	return Term{
		name:     name,
		rootTerm: true,
		termType: termType,
		args:     convertTermList(args),
		optArgs:  convertTermObj(optArgs),
	}
}

// constructMethodTerm is an alias for creating a new term. Unlike constructRootTerm
// this function adds the previous expression in the tree to the argument list to
// create a method term.
func constructMethodTerm(prevVal Term, name string, termType p.Term_TermType, args []interface{}, optArgs map[string]interface{}) Term {
	args = append([]interface{}{prevVal}, args...)

	return Term{
		name:     name,
		rootTerm: false,
		termType: termType,
		args:     convertTermList(args),
		optArgs:  convertTermObj(optArgs),
	}
}

// Helper functions for creating internal RQL types

// makeArray takes a slice of terms and produces a single MAKE_ARRAY term
func makeArray(args termsList) Term {
	return Term{
		name:     "[...]",
		termType: p.Term_MAKE_ARRAY,
		args:     args,
	}
}

// makeObject takes a map of terms and produces a single MAKE_OBJECT term
func makeObject(args termsObj) Term {
	// First all evaluate all fields in the map
	temp := termsObj{}
	for k, v := range args {
		temp[k] = Expr(v)
	}

	return Term{
		name:     "{...}",
		termType: p.Term_MAKE_OBJ,
		optArgs:  temp,
	}
}

var nextVarId int64 = 0

func makeFunc(f interface{}) Term {
	value := reflect.ValueOf(f)
	valueType := value.Type()

	var argNums []interface{}
	var args []reflect.Value
	for i := 0; i < valueType.NumIn(); i++ {
		// Get a slice of the VARs to use as the function arguments
		args = append(args, reflect.ValueOf(constructRootTerm("var", p.Term_VAR, []interface{}{nextVarId}, map[string]interface{}{})))
		argNums = append(argNums, nextVarId)
		atomic.AddInt64(&nextVarId, 1)

		// make sure all input arguments are of type Term
		if valueType.In(i).String() != "gorethink.Term" {
			panic("Function argument is not of type Term")
		}
	}

	if valueType.NumOut() != 1 {
		panic("Function does not have a single return value")
	}

	body := value.Call(args)[0].Interface()
	argsArr := makeArray(convertTermList(argNums))

	return constructRootTerm("func", p.Term_FUNC, []interface{}{argsArr, body}, map[string]interface{}{})
}

func funcWrap(value interface{}) Term {
	val := Expr(value)

	if implVarScan(val) && val.termType != p.Term_ARGS {
		return makeFunc(func(x Term) Term {
			return val
		})
	} else {
		return val
	}
}

func funcWrapArgs(args []interface{}) []interface{} {
	for i, arg := range args {
		args[i] = funcWrap(arg)
	}

	return args
}

// implVarScan recursivly checks a value to see if it contains an
// IMPLICIT_VAR term. If it does it returns true
func implVarScan(value Term) bool {
	if value.termType == p.Term_IMPLICIT_VAR {
		return true
	} else {
		for _, v := range value.args {
			if implVarScan(v) {
				return true
			}
		}

		for _, v := range value.optArgs {
			if implVarScan(v) {
				return true
			}
		}

		return false
	}
}

// Convert an opt args struct to a map.
func optArgsToMap(optArgs OptArgs) map[string]interface{} {
	data, err := encode(optArgs)

	if err == nil && data != nil {
		if m, ok := data.(map[string]interface{}); ok {
			return m
		}
	}

	return map[string]interface{}{}
}

// Convert a list into a slice of terms
func convertTermList(l []interface{}) termsList {
	terms := termsList{}
	for _, v := range l {
		terms = append(terms, Expr(v))
	}

	return terms
}

// Convert a map into a map of terms
func convertTermObj(o map[string]interface{}) termsObj {
	terms := termsObj{}
	for k, v := range o {
		terms[k] = Expr(v)
	}

	return terms
}

func mergeArgs(args ...interface{}) []interface{} {
	newArgs := []interface{}{}

	for _, arg := range args {
		switch v := arg.(type) {
		case []interface{}:
			newArgs = append(newArgs, v...)
		default:
			newArgs = append(newArgs, v)
		}
	}

	return newArgs
}

// Pseudo-type helper functions

func reqlTimeToNativeTime(timestamp float64, timezone string) (time.Time, error) {
	sec, ms := math.Modf(timestamp)

	t := time.Unix(int64(sec), int64(ms*1000*1000*1000))

	// Caclulate the timezone
	if timezone != "" {
		hours, err := strconv.Atoi(timezone[1:3])
		if err != nil {
			return time.Time{}, err
		}
		minutes, err := strconv.Atoi(timezone[4:6])
		if err != nil {
			return time.Time{}, err
		}
		tzOffset := ((hours * 60) + minutes) * 60
		if timezone[:1] == "-" {
			tzOffset = 0 - tzOffset
		}

		t = t.In(time.FixedZone(timezone, tzOffset))
	}

	return t, nil
}

func reqlGroupedDataToObj(obj map[string]interface{}) (interface{}, error) {
	if data, ok := obj["data"]; ok {
		ret := []interface{}{}
		for _, v := range data.([]interface{}) {
			v := v.([]interface{})
			ret = append(ret, map[string]interface{}{
				"group":     v[0],
				"reduction": v[1],
			})
		}
		return ret, nil
	} else {
		return nil, fmt.Errorf("pseudo-type GROUPED_DATA object %v does not have the expected field \"data\"", obj)
	}
}

// Helper functions for debugging

func allArgsToStringSlice(args termsList, optArgs termsObj) []string {
	allArgs := []string{}

	for _, v := range args {
		allArgs = append(allArgs, v.String())
	}
	for k, v := range optArgs {
		allArgs = append(allArgs, k+"="+v.String())
	}

	return allArgs
}

func argsToStringSlice(args termsList) []string {
	allArgs := []string{}

	for _, v := range args {
		allArgs = append(allArgs, v.String())
	}

	return allArgs
}

func optArgsToStringSlice(optArgs termsObj) []string {
	allArgs := []string{}

	for k, v := range optArgs {
		allArgs = append(allArgs, k+"="+v.String())
	}

	return allArgs
}

func prefixLines(s string, prefix string) (result string) {
	for _, line := range strings.Split(s, "\n") {
		result += prefix + line + "\n"
	}
	return
}

func protobufToString(p proto.Message, indentLevel int) string {
	return prefixLines(proto.MarshalTextString(p), strings.Repeat("    ", indentLevel))
}

func encode(v interface{}) (interface{}, error) {
	encoding.RegisterEncodeHook(func(v reflect.Value) (success bool, ret reflect.Value, err error) {
		if v.Type() == reflect.TypeOf(time.Time{}) {
			return true, v, nil
		} else if v.Type() == reflect.TypeOf(Term{}) {
			return true, v, nil
		} else {
			return false, v, nil
		}
	})

	return encoding.Encode(v)
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"
	"strings"
)

// Check if a given filename is a directory
func isDir(filename string) bool {
	fs, err := os.Stat(filename)
	if err != nil {
		return false
	}
	return fs.IsDir()
}

// Check if the given filename exists
func exists(filename string) bool {
	_, err := os.Stat(filename)
	return err == nil
}

// Translate a given URL path to a probable full filename
func url2filename(dirname, urlpath string) string {
	if strings.Contains(urlpath, "..") {
		log.Println("Trying to access URL with ..")
		return dirname + sep
	}
	if strings.HasPrefix(urlpath, "/") {
		return dirname + sep + urlpath[1:]
	}
	return dirname + sep + urlpath
}

// Get a list of filenames from a given directory name (that must exist)
func getFilenames(dirname string) []string {
	dir, err := os.Open(dirname)
	if err != nil {
		log.Fatalf("Could not open directory: %s (%s)", dirname, err)
		return []string{}
	}
	filenames, err := dir.Readdirnames(-1)
	if err != nil {
		log.Fatalf("Could not read filenames from directory: %s (%s)", dirname, err)
		return []string{}
	}
	return filenames
}

func easyPage(title, body string) string {
	return "<!doctype html>" + font + "<title>" + title + "</title>
" + title + "
" + body + ""
}

func easyLink(text, url string, isDirectory bool) string {
	if isDirectory {
		text += "/"
	}
	return "" + text + "
"
}
<commit_msg>Add / to URLs to directories.<commit_after>package main

import (
	"log"
	"os"
	"strings"
)

// Check if a given filename is a directory
func isDir(filename string) bool {
	fs, err := os.Stat(filename)
	if err != nil {
		return false
	}
	return fs.IsDir()
}

// Check if the given filename exists
func exists(filename string) bool {
	_, err := os.Stat(filename)
	return err == nil
}

// Translate a given URL path to a probable full filename
func url2filename(dirname, urlpath string) string {
	if strings.Contains(urlpath, "..") {
		log.Println("Trying to access URL with ..")
		return dirname + sep
	}
	if strings.HasPrefix(urlpath, "/") {
		return dirname + sep + urlpath[1:]
	}
	return dirname + sep + urlpath
}

// Get a list of filenames from a given directory name (that must exist)
func getFilenames(dirname string) []string {
	dir, err := os.Open(dirname)
	if err != nil {
		log.Fatalf("Could not open directory: %s (%s)", dirname, err)
		return []string{}
	}
	filenames, err := dir.Readdirnames(-1)
	if err != nil {
		log.Fatalf("Could not read filenames from directory: %s (%s)", dirname, err)
		return []string{}
	}
	return filenames
}

func easyPage(title, body string) string {
	return "<!doctype html>" + font + "<title>" + title + "</title>
" + title + "
" + body + ""
}

func easyLink(text, url string, isDirectory bool) string {
	if isDirectory {
		text += "/"
	}
	// If the directory only contains one index.* file, adding "/" to the URL is not needed,
	// because no other files will be needed to be accessed from that directory by the index
	// file in question. Just a note.
	return "" + text + "
"
}
<|endoftext|>


<commit_before>package image_ecosystem

import (
	"fmt"
)

type ImageBaseType string

type tc struct {
	// The image version string (eg. '27' or '34')
	Version string
	// Command to execute
	Cmd string
	// Expected output from the command
	Expected string

	// Repository is either openshift/ or rhcsl/
	// The default is 'openshift'
	Repository string

	// Internal: We resolve this in JustBeforeEach
	DockerImageReference string

	// whether this image is supported on s390x or ppc64le
	NonAMD bool
}

// This is a complete list of supported S2I images
var s2iImages = map[string][]tc{
	"ruby": {
		{
			Version:    "27",
			Cmd:        "ruby --version",
			Expected:   "ruby 2.7",
			Repository: "rhscl",
			NonAMD:     true,
		},
		{
			Version:    "26",
			Cmd:        "ruby --version",
			Expected:   "ruby 2.6",
			Repository: "rhscl",
			NonAMD:     true,
		},
	},
	"python": {
		{
			Version:    "27",
			Cmd:        "python --version",
			Expected:   "Python 2.7",
			Repository: "rhscl",
			NonAMD:     true,
		},
		{
			Version:    "36",
			Cmd:        "python --version",
			Expected:   "Python 3.6",
			Repository: "rhscl",
			NonAMD:     true,
		},
	},
	"nodejs": {
		{
			Version:    "10",
			Cmd:        "node --version",
			Expected:   "v10",
			Repository: "rhscl",
			NonAMD:     true,
		},
		{
			Version:    "12",
			Cmd:        "node --version",
			Expected:   "v12",
			Repository: "rhscl",
			NonAMD:     true,
		},
	},
	"perl": {
		{
			Version:    "526",
			Cmd:        "perl --version",
			Expected:   "v5.26",
			Repository: "rhscl",
			NonAMD:     true,
		},
	},
	"php": {
		{
			Version:    "72",
			Cmd:        "php --version",
			Expected:   "7.2",
			Repository: "rhscl",
			NonAMD:     true,
		},
		{
			Version:    "73",
			Cmd:        "php --version",
			Expected:   "7.3",
			Repository: "rhscl",
			NonAMD:     true,
		},
	},
}

func GetTestCaseForImages() map[string][]tc {
	result := make(map[string][]tc)
	for name, variants := range s2iImages {
		for i := range variants {
			resolveDockerImageReference(name, &variants[i])
			result[name] = append(result[name], variants[i])
		}
	}
	return result
}

// resolveDockerImageReferences resolves the pull specs for all images
func resolveDockerImageReference(name string, t *tc) {
	if len(t.Repository) == 0 {
		t.Repository = "openshift"
	}
	t.DockerImageReference = fmt.Sprintf("registry.redhat.io/%s/%s-%s-rhel7", t.Repository, name, t.Version)
}
<commit_msg>replace registry.redhat.io refs with internal image registry refs in image-eco e2e<commit_after>package image_ecosystem

import (
	"fmt"
)

type ImageBaseType string

type tc struct {
	// The image version string (eg. '27' or '34')
	Version string
	// Command to execute
	Cmd string
	// Expected output from the command
	Expected string

	// Tag is the image tag to correlates to the Version string
	Tag string

	// Internal: We resolve this in JustBeforeEach
	DockerImageReference string

	// whether this image is supported on s390x or ppc64le
	NonAMD bool
}

// This is a complete list of supported S2I images
var s2iImages = map[string][]tc{
	"ruby": {
		{
			Version:  "27",
			Cmd:      "ruby --version",
			Expected: "ruby 2.7",
			Tag:      "2.7",
			NonAMD:   true,
		},
		{
			Version:  "26",
			Cmd:      "ruby --version",
			Expected: "ruby 2.6",
			Tag:      "2.6",
			NonAMD:   true,
		},
	},
	"python": {
		{
			Version:  "27",
			Cmd:      "python --version",
			Expected: "Python 2.7",
			Tag:      "2.7",
			NonAMD:   true,
		},
		{
			Version:  "36",
			Cmd:      "python --version",
			Expected: "Python 3.6",
			Tag:      "3.6-ubi8",
			NonAMD:   true,
		},
	},
	"nodejs": {
		{
			Version:  "10",
			Cmd:      "node --version",
			Expected: "v10",
			Tag:      "10",
			NonAMD:   true,
		},
		{
			Version:  "12",
			Cmd:      "node --version",
			Expected: "v12",
			Tag:      "12",
			NonAMD:   true,
		},
	},
	"perl": {
		{
			Version:  "526",
			Cmd:      "perl --version",
			Expected: "v5.26",
			Tag:      "5.26",
			NonAMD:   true,
		},
	},
	"php": {
		{
			Version:  "72",
			Cmd:      "php --version",
			Expected: "7.2",
			Tag:      "7.2-ubi8",
			NonAMD:   true,
		},
		{
			Version:  "73",
			Cmd:      "php --version",
			Expected: "7.3",
			Tag:      "7.3",
			NonAMD:   true,
		},
	},
}

func GetTestCaseForImages() map[string][]tc {
	result := make(map[string][]tc)
	for name, variants := range s2iImages {
		for i := range variants {
			resolveDockerImageReference(name, &variants[i])
			result[name] = append(result[name], variants[i])
		}
	}
	return result
}

// resolveDockerImageReferences resolves the pull specs for all images
func resolveDockerImageReference(name string, t *tc) {
	t.DockerImageReference = fmt.Sprintf("image-registry.openshift-image-registry.svc:5000/openshift/%s:%s", name, t.Tag)
}
<|endoftext|>


<commit_before>package crawler

import (
	"encoding/json"
	"fmt"
	"github.com/dokterbob/ipfs-search/indexer"
	"github.com/dokterbob/ipfs-search/queue"
	"gopkg.in/ipfs/go-ipfs-api.v1"
	"log"
	"net"
	"net/http"
	"net/url"
	// "path"
	"strings"
	"syscall"
	"time"
)

const (
	// Reconnect time in seconds
	RECONNECT_WAIT = 2
	TIKA_TIMEOUT   = 120
)

type CrawlerArgs struct {
	Hash       string
	Name       string
	Size       uint64
	ParentHash string
	ParentName string
}

type Crawler struct {
	sh *shell.Shell
	id *indexer.Indexer
	fq *queue.TaskQueue
	hq *queue.TaskQueue
}

func NewCrawler(sh *shell.Shell, id *indexer.Indexer, fq *queue.TaskQueue, hq *queue.TaskQueue) *Crawler {
	return &Crawler{
		sh: sh,
		id: id,
		fq: fq,
		hq: hq,
	}
}

func hashUrl(hash string) string {
	return fmt.Sprintf("/ipfs/%s", hash)
}

// Helper function for creating reference structure
/*
	'<hash>': {
		'references': {
			[{
				'parent_hash'
				'hash'
				'name'
			}, ]
		}
	}

	if (document_exists) {
		if (references_exists) {
			add_parent_hash to references
		} else {
			add references to document
		}
	} else {
		create document with references as only information
	}
*/
func construct_references(name string, parent_hash string, parent_name string) []map[string]interface{} {
	references := []map[string]interface{}{}

	if name != "" {
		references = []map[string]interface{}{
			{
				"name":        name,
				"parent_hash": parent_hash,
				"parent_name": parent_name,
			},
		}
	}

	return references
}

// Handle IPFS errors graceously, returns try again bool and original error
func (c Crawler) handleError(err error, hash string) (bool, error) {
	if _, ok := err.(*shell.Error); ok && strings.Contains(err.Error(), "proto") {
		// We're not recovering from protocol errors, so panic

		// Attempt to index panic to prevent re-indexing
		metadata := map[string]interface{}{
			"error": err.Error(),
		}

		c.id.IndexItem("invalid", hash, metadata)

		panic(err)
	}

	if uerr, ok := err.(*url.Error); ok {
		// URL errors

		log.Printf("URL error %v", uerr)

		if uerr.Timeout() {
			// Fail on timeouts
			return false, err
		}

		if uerr.Temporary() {
			// Retry on other temp errors
			return true, nil
		}

		// Somehow, the errors below are not temp errors !?
		switch t := uerr.Err.(type) {
		case *net.OpError:
			if t.Op == "dial" {
				log.Printf("Unknown host %v", t)
				return true, nil

			} else if t.Op == "read" {
				log.Printf("Connection refused %v", t)
				return true, nil
			}

		case syscall.Errno:
			if t == syscall.ECONNREFUSED {
				log.Printf("Connection refused %v", t)
				return true, nil
			}
		}
	}

	return false, err
}

// Given a particular hash (file or directory), start crawling
func (c Crawler) CrawlHash(hash string, name string, parent_hash string, parent_name string) error {
	indexed, err := c.id.IsIndexed(hash)
	if err != nil {
		return err
	}

	if indexed {
		log.Printf("Already indexed '%s', skipping", hash)
		return nil
	}

	log.Printf("Crawling hash '%s' (%s)", hash, name)

	url := hashUrl(hash)

	var list *shell.UnixLsObject

	try_again := true
	for try_again {
		list, err = c.sh.FileList(url)

		try_again, err = c.handleError(err, hash)

		if try_again {
			log.Printf("Retrying in %d seconds", RECONNECT_WAIT)
			time.Sleep(RECONNECT_WAIT * time.Duration(time.Second))
		}
	}

	if err != nil {
		return err
	}

	switch list.Type {
	case "File":
		// Add to file crawl queue
		// Note: we're expecting no references here, see comment below
		args := CrawlerArgs{
			Hash: hash,
			Name: name,
			Size: list.Size,
		}

		err = c.fq.AddTask(args)
		if err != nil {
			// failed to send the task
			return err
		}
	case "Directory":
		// Index name and size for directory and directory items
		properties := map[string]interface{}{
			"links":      list.Links,
			"size":       list.Size,
			"references": construct_references(name, parent_hash, parent_name),
		}

		err := c.id.IndexItem("directory", hash, properties)
		if err != nil {
			return err
		}

		for _, link := range list.Links {
			args := CrawlerArgs{
				Hash:       link.Hash,
				Name:       link.Name,
				Size:       link.Size,
				ParentHash: hash,
				ParentName: name,
			}

			switch link.Type {
			case "File":
				// Add file to crawl queue
				err = c.fq.AddTask(args)
				if err != nil {
					// failed to send the task
					return err
				}

			case "Directory":
				// Add directory to crawl queue
				c.hq.AddTask(args)
				if err != nil {
					// failed to send the task
					return err
				}
			default:
				log.Printf("Type '%s' skipped for '%s'", list.Type, hash)
			}
		}
	default:
		log.Printf("Type '%s' skipped for '%s'", list.Type, hash)
	}

	log.Printf("Finished hash %s", hash)

	return nil
}

func getMetadata(path string, metadata *map[string]interface{}) error {
	const ipfs_tika_url = "http://localhost:8081"

	client := http.Client{
		Timeout: TIKA_TIMEOUT * time.Duration(time.Second),
	}

	resp, err := client.Get(ipfs_tika_url + path)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	// Parse resulting JSON
	if err := json.NewDecoder(resp.Body).Decode(&metadata); err != nil {
		return err
	}

	return err
}

// Crawl a single object, known to be a file
func (c Crawler) CrawlFile(hash string, name string, parent_hash string, parent_name string, size uint64) error {
	indexed, err := c.id.IsIndexed(hash)
	if err != nil {
		return err
	}

	if indexed {
		log.Printf("Already indexed '%s', skipping", hash)
		return nil
	}

	log.Printf("Crawling file %s (%s)\n", hash, name)

	metadata := make(map[string]interface{})

	if size > 0 {
		if size > 10*1024*1024 {
			// Fail hard for really large files, for now
			return fmt.Errorf("%s (%s) too large, not indexing (for now).", hash, name)
		}

		var path string
		if name != "" && parent_hash != "" {
			path = fmt.Sprintf("/ipfs/%s/%s", parent_hash, name)
		} else {
			path = fmt.Sprintf("/ipfs/%s", hash)
		}

		try_again := true
		for try_again {
			err = getMetadata(path, &metadata)

			try_again, err = c.handleError(err, hash)

			if try_again {
				log.Printf("Retrying in %d seconds", RECONNECT_WAIT)
				time.Sleep(RECONNECT_WAIT * time.Duration(time.Second))
			}
		}

		if err != nil {
			return err
		}

		// Check for IPFS links in content
		/*
			for raw_url := range metadata.urls {
				url, err := URL.Parse(raw_url)

				if err != nil {
					return err
				}

				if strings.HasPrefix(url.Path, "/ipfs/") {
					// Found IPFS link!
					args := CrawlerArgs{
						Hash:       link.Hash,
						Name:       link.Name,
						Size:       link.Size,
						ParentHash: hash,
						ParentName: name,
					}

				}
			}
		*/
	}

	metadata["size"] = size
	metadata["references"] = construct_references(name, parent_hash, parent_name)

	err = c.id.IndexItem("file", hash, metadata)
	if err != nil {
		return err
	}

	log.Printf("Finished file %s", hash)

	return nil
}
<commit_msg>Check status code, prevent file indexer to continue when Tika fails.<commit_after>package crawler

import (
	"encoding/json"
	"fmt"
	"github.com/dokterbob/ipfs-search/indexer"
	"github.com/dokterbob/ipfs-search/queue"
	"gopkg.in/ipfs/go-ipfs-api.v1"
	"log"
	"net"
	"net/http"
	"net/url"
	// "path"
	"strings"
	"syscall"
	"time"
)

const (
	// Reconnect time in seconds
	RECONNECT_WAIT = 2
	TIKA_TIMEOUT   = 120
)

type CrawlerArgs struct {
	Hash       string
	Name       string
	Size       uint64
	ParentHash string
	ParentName string
}

type Crawler struct {
	sh *shell.Shell
	id *indexer.Indexer
	fq *queue.TaskQueue
	hq *queue.TaskQueue
}

func NewCrawler(sh *shell.Shell, id *indexer.Indexer, fq *queue.TaskQueue, hq *queue.TaskQueue) *Crawler {
	return &Crawler{
		sh: sh,
		id: id,
		fq: fq,
		hq: hq,
	}
}

func hashUrl(hash string) string {
	return fmt.Sprintf("/ipfs/%s", hash)
}

// Helper function for creating reference structure
/*
	'<hash>': {
		'references': {
			[{
				'parent_hash'
				'hash'
				'name'
			}, ]
		}
	}

	if (document_exists) {
		if (references_exists) {
			add_parent_hash to references
		} else {
			add references to document
		}
	} else {
		create document with references as only information
	}
*/
func construct_references(name string, parent_hash string, parent_name string) []map[string]interface{} {
	references := []map[string]interface{}{}

	if name != "" {
		references = []map[string]interface{}{
			{
				"name":        name,
				"parent_hash": parent_hash,
				"parent_name": parent_name,
			},
		}
	}

	return references
}

// Handle IPFS errors graceously, returns try again bool and original error
func (c Crawler) handleError(err error, hash string) (bool, error) {
	if _, ok := err.(*shell.Error); ok && strings.Contains(err.Error(), "proto") {
		// We're not recovering from protocol errors, so panic

		// Attempt to index panic to prevent re-indexing
		metadata := map[string]interface{}{
			"error": err.Error(),
		}

		c.id.IndexItem("invalid", hash, metadata)

		panic(err)
	}

	if uerr, ok := err.(*url.Error); ok {
		// URL errors

		log.Printf("URL error %v", uerr)

		if uerr.Timeout() {
			// Fail on timeouts
			return false, err
		}

		if uerr.Temporary() {
			// Retry on other temp errors
			return true, nil
		}

		// Somehow, the errors below are not temp errors !?
		switch t := uerr.Err.(type) {
		case *net.OpError:
			if t.Op == "dial" {
				log.Printf("Unknown host %v", t)
				return true, nil

			} else if t.Op == "read" {
				log.Printf("Connection refused %v", t)
				return true, nil
			}

		case syscall.Errno:
			if t == syscall.ECONNREFUSED {
				log.Printf("Connection refused %v", t)
				return true, nil
			}
		}
	}

	return false, err
}

// Given a particular hash (file or directory), start crawling
func (c Crawler) CrawlHash(hash string, name string, parent_hash string, parent_name string) error {
	indexed, err := c.id.IsIndexed(hash)
	if err != nil {
		return err
	}

	if indexed {
		log.Printf("Already indexed '%s', skipping", hash)
		return nil
	}

	log.Printf("Crawling hash '%s' (%s)", hash, name)

	url := hashUrl(hash)

	var list *shell.UnixLsObject

	try_again := true
	for try_again {
		list, err = c.sh.FileList(url)

		try_again, err = c.handleError(err, hash)

		if try_again {
			log.Printf("Retrying in %d seconds", RECONNECT_WAIT)
			time.Sleep(RECONNECT_WAIT * time.Duration(time.Second))
		}
	}

	if err != nil {
		return err
	}

	switch list.Type {
	case "File":
		// Add to file crawl queue
		// Note: we're expecting no references here, see comment below
		args := CrawlerArgs{
			Hash: hash,
			Name: name,
			Size: list.Size,
		}

		err = c.fq.AddTask(args)
		if err != nil {
			// failed to send the task
			return err
		}
	case "Directory":
		// Index name and size for directory and directory items
		properties := map[string]interface{}{
			"links":      list.Links,
			"size":       list.Size,
			"references": construct_references(name, parent_hash, parent_name),
		}

		err := c.id.IndexItem("directory", hash, properties)
		if err != nil {
			return err
		}

		for _, link := range list.Links {
			args := CrawlerArgs{
				Hash:       link.Hash,
				Name:       link.Name,
				Size:       link.Size,
				ParentHash: hash,
				ParentName: name,
			}

			switch link.Type {
			case "File":
				// Add file to crawl queue
				err = c.fq.AddTask(args)
				if err != nil {
					// failed to send the task
					return err
				}

			case "Directory":
				// Add directory to crawl queue
				c.hq.AddTask(args)
				if err != nil {
					// failed to send the task
					return err
				}
			default:
				log.Printf("Type '%s' skipped for '%s'", list.Type, hash)
			}
		}
	default:
		log.Printf("Type '%s' skipped for '%s'", list.Type, hash)
	}

	log.Printf("Finished hash %s", hash)

	return nil
}

func getMetadata(path string, metadata *map[string]interface{}) error {
	const ipfs_tika_url = "http://localhost:8081"

	client := http.Client{
		Timeout: TIKA_TIMEOUT * time.Duration(time.Second),
	}

	resp, err := client.Get(ipfs_tika_url + path)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		return fmt.Errorf("Undesired status '%s' from ipfs-tika.", resp.Status)
	}

	// Parse resulting JSON
	if err := json.NewDecoder(resp.Body).Decode(&metadata); err != nil {
		return err
	}

	return err
}

// Crawl a single object, known to be a file
func (c Crawler) CrawlFile(hash string, name string, parent_hash string, parent_name string, size uint64) error {
	indexed, err := c.id.IsIndexed(hash)
	if err != nil {
		return err
	}

	if indexed {
		log.Printf("Already indexed '%s', skipping", hash)
		return nil
	}

	log.Printf("Crawling file %s (%s)\n", hash, name)

	metadata := make(map[string]interface{})

	if size > 0 {
		if size > 10*1024*1024 {
			// Fail hard for really large files, for now
			return fmt.Errorf("%s (%s) too large, not indexing (for now).", hash, name)
		}

		var path string
		if name != "" && parent_hash != "" {
			path = fmt.Sprintf("/ipfs/%s/%s", parent_hash, name)
		} else {
			path = fmt.Sprintf("/ipfs/%s", hash)
		}

		try_again := true
		for try_again {
			err = getMetadata(path, &metadata)

			try_again, err = c.handleError(err, hash)

			if try_again {
				log.Printf("Retrying in %d seconds", RECONNECT_WAIT)
				time.Sleep(RECONNECT_WAIT * time.Duration(time.Second))
			}
		}

		if err != nil {
			return err
		}

		// Check for IPFS links in content
		/*
			for raw_url := range metadata.urls {
				url, err := URL.Parse(raw_url)

				if err != nil {
					return err
				}

				if strings.HasPrefix(url.Path, "/ipfs/") {
					// Found IPFS link!
					args := CrawlerArgs{
						Hash:       link.Hash,
						Name:       link.Name,
						Size:       link.Size,
						ParentHash: hash,
						ParentName: name,
					}

				}
			}
		*/
	}

	metadata["size"] = size
	metadata["references"] = construct_references(name, parent_hash, parent_name)

	err = c.id.IndexItem("file", hash, metadata)
	if err != nil {
		return err
	}

	log.Printf("Finished file %s", hash)

	return nil
}
<|endoftext|>


<commit_before>// The nodefs package offers a high level API that resembles the
// kernel's idea of what an FS looks like.  File systems can have
// multiple hard-links to one file, for example. It is also suited if
// the data to represent fits in memory: you can construct the
// complete file system tree at mount time
package nodefs

import (
	"time"

	"github.com/hanwen/go-fuse/fuse"
)

// This is a legacy type.
type FileSystem interface {
	// Root should return the inode for root of this file system.
	Root() Node

	// Used for debug outputs
	String() string

	// If called, provide debug output through the log package.
	SetDebug(debug bool)
}

// The Node interface implements the user-defined file system
// functionality
type Node interface {
	// Inode and SetInode are basic getter/setters.  They are
	// called by the FileSystemConnector. You get them for free by
	// embedding the result of NewDefaultNode() in your node
	// struct.
	Inode() *Inode
	SetInode(node *Inode)

	// OnMount is called on the root node just after a mount is
	// executed, either when the actual root is mounted, or when a
	// filesystem is mounted in-process. The passed-in
	// FileSystemConnector gives access to Notify methods and
	// Debug settings.
	OnMount(conn *FileSystemConnector)

	// OnUnmount is executed just before a submount is removed,
	// and when the process receives a forget for the FUSE root
	// node.
	OnUnmount()

	// Lookup finds a child node to this node; it is only called
	// for directory Nodes.
	Lookup(out *fuse.Attr, name string, context *fuse.Context) (*Inode, fuse.Status)

	// Deletable() should return true if this inode may be
	// discarded from the children list. This will be called from
	// within the treeLock critical section, so you cannot look at
	// other inodes.
	Deletable() bool

	// OnForget is called when the reference to this inode is
	// dropped from the tree.
	OnForget()

	// Misc.
	Access(mode uint32, context *fuse.Context) (code fuse.Status)
	Readlink(c *fuse.Context) ([]byte, fuse.Status)

	// Namespace operations; these are only called on directory Nodes.

	// Mknod should create the node, add it to the receiver's
	// inode, and return it
	Mknod(name string, mode uint32, dev uint32, context *fuse.Context) (newNode *Inode, code fuse.Status)

	// Mkdir should create the directory Inode, add it to the
	// receiver's Inode, and return it
	Mkdir(name string, mode uint32, context *fuse.Context) (newNode *Inode, code fuse.Status)
	Unlink(name string, context *fuse.Context) (code fuse.Status)
	Rmdir(name string, context *fuse.Context) (code fuse.Status)

	// Symlink should create a child inode to the receiver, and
	// return it.
	Symlink(name string, content string, context *fuse.Context) (*Inode, fuse.Status)
	Rename(oldName string, newParent Node, newName string, context *fuse.Context) (code fuse.Status)

	// Link should return the Inode of the resulting link. In
	// a POSIX conformant file system, this should add 'existing'
	// to the receiver, and return the Inode corresponding to
	// 'existing'.
	Link(name string, existing Node, context *fuse.Context) (newNode *Inode, code fuse.Status)

	// Create should return an open file, and the Inode for that file.
	Create(name string, flags uint32, mode uint32, context *fuse.Context) (file File, child *Inode, code fuse.Status)
	Open(flags uint32, context *fuse.Context) (file File, code fuse.Status)
	OpenDir(context *fuse.Context) ([]fuse.DirEntry, fuse.Status)

	// XAttrs
	GetXAttr(attribute string, context *fuse.Context) (data []byte, code fuse.Status)
	RemoveXAttr(attr string, context *fuse.Context) fuse.Status
	SetXAttr(attr string, data []byte, flags int, context *fuse.Context) fuse.Status
	ListXAttr(context *fuse.Context) (attrs []string, code fuse.Status)

	// Attributes
	GetAttr(out *fuse.Attr, file File, context *fuse.Context) (code fuse.Status)
	Chmod(file File, perms uint32, context *fuse.Context) (code fuse.Status)
	Chown(file File, uid uint32, gid uint32, context *fuse.Context) (code fuse.Status)
	Truncate(file File, size uint64, context *fuse.Context) (code fuse.Status)
	Utimens(file File, atime *time.Time, mtime *time.Time, context *fuse.Context) (code fuse.Status)
	Fallocate(file File, off uint64, size uint64, mode uint32, context *fuse.Context) (code fuse.Status)

	StatFs() *fuse.StatfsOut
}

// A File object should be returned from FileSystem.Open and
// FileSystem.Create.  Include the NewDefaultFile return value into
// the struct to inherit a default null implementation.
type File interface {
	// Called upon registering the filehandle in the inode.
	SetInode(*Inode)

	// The String method is for debug printing.
	String() string

	// Wrappers around other File implementations, should return
	// the inner file here.
	InnerFile() File

	Read(dest []byte, off int64) (fuse.ReadResult, fuse.Status)
	Write(data []byte, off int64) (written uint32, code fuse.Status)
	Flush() fuse.Status
	Release()
	Fsync(flags int) (code fuse.Status)

	// The methods below may be called on closed files, due to
	// concurrency.  In that case, you should return EBADF.
	Truncate(size uint64) fuse.Status
	GetAttr(out *fuse.Attr) fuse.Status
	Chown(uid uint32, gid uint32) fuse.Status
	Chmod(perms uint32) fuse.Status
	Utimens(atime *time.Time, mtime *time.Time) fuse.Status
	Allocate(off uint64, size uint64, mode uint32) (code fuse.Status)
}

// Wrap a File return in this to set FUSE flags.  Also used internally
// to store open file data.
type WithFlags struct {
	File

	// For debugging.
	Description string

	// Put FOPEN_* flags here.
	FuseFlags uint32

	// O_RDWR, O_TRUNCATE, etc.
	OpenFlags uint32
}

// Options contains time out options for a node FileSystem.  The
// default copied from libfuse and set in NewMountOptions() is
// (1s,1s,0s).
type Options struct {
	EntryTimeout    time.Duration
	AttrTimeout     time.Duration
	NegativeTimeout time.Duration

	// If set, replace all uids with given UID.
	// NewFileSystemOptions() will set this to the daemon's
	// uid/gid.
	*fuse.Owner

	// If set, use a more portable, but slower inode number
	// generation scheme.  This will make inode numbers (exported
	// back to callers) stay within int32, which is necessary for
	// making stat() succeed in 32-bit programs.
	PortableInodes bool
}
<commit_msg>fuse/nodefs: document File.Release vs. File.Flush.<commit_after>// The nodefs package offers a high level API that resembles the
// kernel's idea of what an FS looks like.  File systems can have
// multiple hard-links to one file, for example. It is also suited if
// the data to represent fits in memory: you can construct the
// complete file system tree at mount time
package nodefs

import (
	"time"

	"github.com/hanwen/go-fuse/fuse"
)

// This is a legacy type.
type FileSystem interface {
	// Root should return the inode for root of this file system.
	Root() Node

	// Used for debug outputs
	String() string

	// If called, provide debug output through the log package.
	SetDebug(debug bool)
}

// The Node interface implements the user-defined file system
// functionality
type Node interface {
	// Inode and SetInode are basic getter/setters.  They are
	// called by the FileSystemConnector. You get them for free by
	// embedding the result of NewDefaultNode() in your node
	// struct.
	Inode() *Inode
	SetInode(node *Inode)

	// OnMount is called on the root node just after a mount is
	// executed, either when the actual root is mounted, or when a
	// filesystem is mounted in-process. The passed-in
	// FileSystemConnector gives access to Notify methods and
	// Debug settings.
	OnMount(conn *FileSystemConnector)

	// OnUnmount is executed just before a submount is removed,
	// and when the process receives a forget for the FUSE root
	// node.
	OnUnmount()

	// Lookup finds a child node to this node; it is only called
	// for directory Nodes.
	Lookup(out *fuse.Attr, name string, context *fuse.Context) (*Inode, fuse.Status)

	// Deletable() should return true if this inode may be
	// discarded from the children list. This will be called from
	// within the treeLock critical section, so you cannot look at
	// other inodes.
	Deletable() bool

	// OnForget is called when the reference to this inode is
	// dropped from the tree.
	OnForget()

	// Misc.
	Access(mode uint32, context *fuse.Context) (code fuse.Status)
	Readlink(c *fuse.Context) ([]byte, fuse.Status)

	// Namespace operations; these are only called on directory Nodes.

	// Mknod should create the node, add it to the receiver's
	// inode, and return it
	Mknod(name string, mode uint32, dev uint32, context *fuse.Context) (newNode *Inode, code fuse.Status)

	// Mkdir should create the directory Inode, add it to the
	// receiver's Inode, and return it
	Mkdir(name string, mode uint32, context *fuse.Context) (newNode *Inode, code fuse.Status)
	Unlink(name string, context *fuse.Context) (code fuse.Status)
	Rmdir(name string, context *fuse.Context) (code fuse.Status)

	// Symlink should create a child inode to the receiver, and
	// return it.
	Symlink(name string, content string, context *fuse.Context) (*Inode, fuse.Status)
	Rename(oldName string, newParent Node, newName string, context *fuse.Context) (code fuse.Status)

	// Link should return the Inode of the resulting link. In
	// a POSIX conformant file system, this should add 'existing'
	// to the receiver, and return the Inode corresponding to
	// 'existing'.
	Link(name string, existing Node, context *fuse.Context) (newNode *Inode, code fuse.Status)

	// Create should return an open file, and the Inode for that file.
	Create(name string, flags uint32, mode uint32, context *fuse.Context) (file File, child *Inode, code fuse.Status)
	Open(flags uint32, context *fuse.Context) (file File, code fuse.Status)
	OpenDir(context *fuse.Context) ([]fuse.DirEntry, fuse.Status)

	// XAttrs
	GetXAttr(attribute string, context *fuse.Context) (data []byte, code fuse.Status)
	RemoveXAttr(attr string, context *fuse.Context) fuse.Status
	SetXAttr(attr string, data []byte, flags int, context *fuse.Context) fuse.Status
	ListXAttr(context *fuse.Context) (attrs []string, code fuse.Status)

	// Attributes
	GetAttr(out *fuse.Attr, file File, context *fuse.Context) (code fuse.Status)
	Chmod(file File, perms uint32, context *fuse.Context) (code fuse.Status)
	Chown(file File, uid uint32, gid uint32, context *fuse.Context) (code fuse.Status)
	Truncate(file File, size uint64, context *fuse.Context) (code fuse.Status)
	Utimens(file File, atime *time.Time, mtime *time.Time, context *fuse.Context) (code fuse.Status)
	Fallocate(file File, off uint64, size uint64, mode uint32, context *fuse.Context) (code fuse.Status)

	StatFs() *fuse.StatfsOut
}

// A File object should be returned from FileSystem.Open and
// FileSystem.Create.  Include the NewDefaultFile return value into
// the struct to inherit a null implementation.
type File interface {
	// Called upon registering the filehandle in the inode.
	SetInode(*Inode)

	// The String method is for debug printing.
	String() string

	// Wrappers around other File implementations, should return
	// the inner file here.
	InnerFile() File

	Read(dest []byte, off int64) (fuse.ReadResult, fuse.Status)
	Write(data []byte, off int64) (written uint32, code fuse.Status)

	// Flush is called for close() call on a file descriptor. In
	// case of duplicated descriptor, it may be called more than
	// once for a file.
	Flush() fuse.Status

	// This is called to before the file handle is forgotten. This
	// method has no return value, so nothing can synchronizes on
	// the call. Any cleanup that requires specific synchronization or
	// could fail with I/O errors should happen in Flush instead.
	Release()
	Fsync(flags int) (code fuse.Status)

	// The methods below may be called on closed files, due to
	// concurrency.  In that case, you should return EBADF.
	Truncate(size uint64) fuse.Status
	GetAttr(out *fuse.Attr) fuse.Status
	Chown(uid uint32, gid uint32) fuse.Status
	Chmod(perms uint32) fuse.Status
	Utimens(atime *time.Time, mtime *time.Time) fuse.Status
	Allocate(off uint64, size uint64, mode uint32) (code fuse.Status)
}

// Wrap a File return in this to set FUSE flags.  Also used internally
// to store open file data.
type WithFlags struct {
	File

	// For debugging.
	Description string

	// Put FOPEN_* flags here.
	FuseFlags uint32

	// O_RDWR, O_TRUNCATE, etc.
	OpenFlags uint32
}

// Options contains time out options for a node FileSystem.  The
// default copied from libfuse and set in NewMountOptions() is
// (1s,1s,0s).
type Options struct {
	EntryTimeout    time.Duration
	AttrTimeout     time.Duration
	NegativeTimeout time.Duration

	// If set, replace all uids with given UID.
	// NewFileSystemOptions() will set this to the daemon's
	// uid/gid.
	*fuse.Owner

	// If set, use a more portable, but slower inode number
	// generation scheme.  This will make inode numbers (exported
	// back to callers) stay within int32, which is necessary for
	// making stat() succeed in 32-bit programs.
	PortableInodes bool
}
<|endoftext|>


<commit_before><commit_msg>removed unnecessary if statement<commit_after><|endoftext|>


<commit_before><commit_msg>Sighs all round.<commit_after><|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.

// A Go scanner. Takes a []byte as source which can then be
// tokenized through repeated calls to the Scan() function.
//
// Sample use:
//
//	import "token"
//	import "scanner"
//
//	func tokenize(src []byte) {
//		var s scanner.Scanner;
//		s.Init(src, nil /* no error handler */, false /* ignore comments */);
//		for {
//			pos, tok, lit := s.Scan();
//			if tok == Scanner.EOF {
//				return;
//			}
//			println(pos, token.TokenString(tok), string(lit));
//		}
//	}
//
package scanner

import (
	"utf8";
	"unicode";
	"strconv";
	"token";
)

// An implementation of an ErrorHandler must be provided to the Scanner.
// If a syntax error is encountered, Error() is called with the exact
// token position (the byte position of the token in the source) and the
// error message.
//
type ErrorHandler interface {
	Error(pos int, msg string);
}

// A Scanner holds the scanner's internal state while processing
// a given text.  It can be allocated as part of another data
// structure but must be initialized via Init() before use.
// See also the package comment for a sample use.
//
type Scanner struct {
	// immutable state
	src []byte;  // source
	err ErrorHandler;  // error reporting
	scan_comments bool;  // if set, comments are reported as tokens

	// scanning state
	pos int;  // current reading position
	ch int;  // one char look-ahead
	chpos int;  // position of ch
}

func isLetter(ch int) bool {
	return
		'a' <= ch && ch <= 'z' ||
		'A' <= ch && ch <= 'Z' ||
		ch == '_' ||
		ch >= 0x80 && unicode.IsLetter(ch);
}

func digitVal(ch int) int {
	switch {
	case '0' <= ch && ch <= '9': return ch - '0';
	case 'a' <= ch && ch <= 'f': return ch - 'a' + 10;
	case 'A' <= ch && ch <= 'F': return ch - 'A' + 10;
	}
	return 16;  // larger than any legal digit val
}

// Read the next Unicode char into S.ch.
// S.ch < 0 means end-of-file.
func (S *Scanner) next() {
	if S.pos < len(S.src) {
		// assume ASCII
		r, w := int(S.src[S.pos]), 1;
		if r >= 0x80 {
			// not ASCII
			r, w = utf8.DecodeRune(S.src[S.pos : len(S.src)]);
		}
		S.ch = r;
		S.chpos = S.pos;
		S.pos += w;
	} else {
		S.ch = -1;  // eof
		S.chpos = len(S.src);
	}
}

// Init() prepares the scanner S to tokenize the text src. Calls to Scan()
// will use the error handler err if they encounter a syntax error. The boolean
// scan_comments specifies whether newline characters and comments should be
// recognized and returned by Scan as token.COMMENT. If scan_comments is false,
// they are treated as white space and ignored.
//
func (S *Scanner) Init(src []byte, err ErrorHandler, scan_comments bool) {
	S.src = src;
	S.err = err;
	S.scan_comments = scan_comments;
	S.next();
}

func charString(ch int) string {
	s := string(ch);
	switch ch {
	case '\a': s = `\a`;
	case '\b': s = `\b`;
	case '\f': s = `\f`;
	case '\n': s = `\n`;
	case '\r': s = `\r`;
	case '\t': s = `\t`;
	case '\v': s = `\v`;
	case '\\': s = `\\`;
	case '\'': s = `\'`;
	}
	return "'" + s + "' (U+" + strconv.Itob(ch, 16) + ")";
}

func (S *Scanner) error(pos int, msg string) {
	S.err.Error(pos, msg);
}

func (S *Scanner) expect(ch int) {
	if S.ch != ch {
		S.error(S.chpos, "expected " + charString(ch) + ", found " + charString(S.ch));
	}
	S.next();  // always make progress
}

func (S *Scanner) skipWhitespace() {
	for {
		switch S.ch {
		case '\t', '\r', ' ':
			// nothing to do
		case '\n':
			if S.scan_comments {
				return;
			}
		default:
			return;
		}
		S.next();
	}
	panic("UNREACHABLE");
}

func (S *Scanner) scanComment() []byte {
	// first '/' already consumed
	pos := S.chpos - 1;

	if S.ch == '/' {
		//-style comment
		for S.ch >= 0 {
			S.next();
			if S.ch == '\n' {
				// '\n' terminates comment but we do not include
				// it in the comment (otherwise we don't see the
				// start of a newline in skipWhitespace()).
				return S.src[pos : S.chpos];
			}
		}

	} else {
		/*-style comment */
		S.expect('*');
		for S.ch >= 0 {
			ch := S.ch;
			S.next();
			if ch == '*' && S.ch == '/' {
				S.next();
				return S.src[pos : S.chpos];
			}
		}
	}

	S.error(pos, "comment not terminated");
	return S.src[pos : S.chpos];
}

func (S *Scanner) scanIdentifier() (tok int, lit []byte) {
	pos := S.chpos;
	for isLetter(S.ch) || digitVal(S.ch) < 10 {
		S.next();
	}
	lit = S.src[pos : S.chpos];
	return token.Lookup(lit), lit;
}

func (S *Scanner) scanMantissa(base int) {
	for digitVal(S.ch) < base {
		S.next();
	}
}

func (S *Scanner) scanNumber(seen_decimal_point bool) (tok int, lit []byte) {
	pos := S.chpos;
	tok = token.INT;

	if seen_decimal_point {
		tok = token.FLOAT;
		pos--;  // '.' is one byte
		S.scanMantissa(10);
		goto exponent;
	}

	if S.ch == '0' {
		// int or float
		S.next();
		if S.ch == 'x' || S.ch == 'X' {
			// hexadecimal int
			S.next();
			S.scanMantissa(16);
		} else {
			// octal int or float
			S.scanMantissa(8);
			if digitVal(S.ch) < 10 || S.ch == '.' || S.ch == 'e' || S.ch == 'E' {
				// float
				tok = token.FLOAT;
				goto mantissa;
			}
			// octal int
		}
		goto exit;
	}

mantissa:
	// decimal int or float
	S.scanMantissa(10);

	if S.ch == '.' {
		// float
		tok = token.FLOAT;
		S.next();
		S.scanMantissa(10)
	}

exponent:
	if S.ch == 'e' || S.ch == 'E' {
		// float
		tok = token.FLOAT;
		S.next();
		if S.ch == '-' || S.ch == '+' {
			S.next();
		}
		S.scanMantissa(10);
	}

exit:
	return tok, S.src[pos : S.chpos];
}

func (S *Scanner) scanDigits(n int, base int) {
	for digitVal(S.ch) < base {
		S.next();
		n--;
	}
	if n > 0 {
		S.error(S.chpos, "illegal char escape");
	}
}

func (S *Scanner) scanEscape(quote int) {
	ch := S.ch;
	pos := S.chpos;
	S.next();
	switch ch {
	case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', quote:
		// nothing to do
	case '0', '1', '2', '3', '4', '5', '6', '7':
		S.scanDigits(3 - 1, 8);  // 1 char read already
	case 'x':
		S.scanDigits(2, 16);
	case 'u':
		S.scanDigits(4, 16);
	case 'U':
		S.scanDigits(8, 16);
	default:
		S.error(pos, "illegal char escape");
	}
}

func (S *Scanner) scanChar() []byte {
	// '\'' already consumed

	pos := S.chpos - 1;
	ch := S.ch;
	S.next();
	if ch == '\\' {
		S.scanEscape('\'');
	}

	S.expect('\'');
	return S.src[pos : S.chpos];
}

func (S *Scanner) scanString() []byte {
	// '"' already consumed

	pos := S.chpos - 1;
	for S.ch != '"' {
		ch := S.ch;
		S.next();
		if ch == '\n' || ch < 0 {
			S.error(pos, "string not terminated");
			break;
		}
		if ch == '\\' {
			S.scanEscape('"');
		}
	}

	S.next();
	return S.src[pos : S.chpos];
}

func (S *Scanner) scanRawString() []byte {
	// '`' already consumed

	pos := S.chpos - 1;
	for S.ch != '`' {
		ch := S.ch;
		S.next();
		if ch == '\n' || ch < 0 {
			S.error(pos, "string not terminated");
			break;
		}
	}

	S.next();
	return S.src[pos : S.chpos];
}

// Helper functions for scanning multi-byte tokens such as >> += >>= .
// Different routines recognize different length tok_i based on matches
// of ch_i. If a token ends in '=', the result is tok1 or tok3
// respectively. Otherwise, the result is tok0 if there was no other
// matching character, or tok2 if the matching character was ch2.

func (S *Scanner) switch2(tok0, tok1 int) int {
	if S.ch == '=' {
		S.next();
		return tok1;
	}
	return tok0;
}

func (S *Scanner) switch3(tok0, tok1, ch2, tok2 int) int {
	if S.ch == '=' {
		S.next();
		return tok1;
	}
	if S.ch == ch2 {
		S.next();
		return tok2;
	}
	return tok0;
}

func (S *Scanner) switch4(tok0, tok1, ch2, tok2, tok3 int) int {
	if S.ch == '=' {
		S.next();
		return tok1;
	}
	if S.ch == ch2 {
		S.next();
		if S.ch == '=' {
			S.next();
			return tok3;
		}
		return tok2;
	}
	return tok0;
}

// Scan() scans the next token and returns the token byte position in the
// source, its token value, and the corresponding literal text if the token
// is an identifier, basic type literal (token.IsLiteral(tok) == true), or
// comment.
//
func (S *Scanner) Scan() (pos, tok int, lit []byte) {
scan_again:
	S.skipWhitespace();

	pos, tok = S.chpos, token.ILLEGAL;

	switch ch := S.ch; {
	case isLetter(ch):
		tok, lit = S.scanIdentifier();
	case digitVal(ch) < 10:
		tok, lit = S.scanNumber(false);
	default:
		S.next();  // always make progress
		switch ch {
		case -1  : tok = token.EOF;
		case '\n': tok, lit = token.COMMENT, []byte{'\n'};
		case '"' : tok, lit = token.STRING, S.scanString();
		case '\'': tok, lit = token.CHAR, S.scanChar();
		case '`' : tok, lit = token.STRING, S.scanRawString();
		case ':' : tok = S.switch2(token.COLON, token.DEFINE);
		case '.' :
			if digitVal(S.ch) < 10 {
				tok, lit = S.scanNumber(true);
			} else if S.ch == '.' {
				S.next();
				if S.ch == '.' {
					S.next();
					tok = token.ELLIPSIS;
				}
			} else {
				tok = token.PERIOD;
			}
		case ',': tok = token.COMMA;
		case ';': tok = token.SEMICOLON;
		case '(': tok = token.LPAREN;
		case ')': tok = token.RPAREN;
		case '[': tok = token.LBRACK;
		case ']': tok = token.RBRACK;
		case '{': tok = token.LBRACE;
		case '}': tok = token.RBRACE;
		case '+': tok = S.switch3(token.ADD, token.ADD_ASSIGN, '+', token.INC);
		case '-': tok = S.switch3(token.SUB, token.SUB_ASSIGN, '-', token.DEC);
		case '*': tok = S.switch2(token.MUL, token.MUL_ASSIGN);
		case '/':
			if S.ch == '/' || S.ch == '*' {
				tok, lit = token.COMMENT, S.scanComment();
				if !S.scan_comments {
					goto scan_again;
				}
			} else {
				tok = S.switch2(token.QUO, token.QUO_ASSIGN);
			}
		case '%': tok = S.switch2(token.REM, token.REM_ASSIGN);
		case '^': tok = S.switch2(token.XOR, token.XOR_ASSIGN);
		case '<':
			if S.ch == '-' {
				S.next();
				tok = token.ARROW;
			} else {
				tok = S.switch4(token.LSS, token.LEQ, '<', token.SHL, token.SHL_ASSIGN);
			}
		case '>': tok = S.switch4(token.GTR, token.GEQ, '>', token.SHR, token.SHR_ASSIGN);
		case '=': tok = S.switch2(token.ASSIGN, token.EQL);
		case '!': tok = S.switch2(token.NOT, token.NEQ);
		case '&': tok = S.switch3(token.AND, token.AND_ASSIGN, '&', token.LAND);
		case '|': tok = S.switch3(token.OR, token.OR_ASSIGN, '|', token.LOR);
		default: S.error(pos, "illegal character " + charString(ch));
		}
	}

	return pos, tok, lit;
}
<commit_msg>Fixing comment.<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.

// A scanner for Go source text. Takes a []byte as source which can
// then be tokenized through repeated calls to the Scan() function.
//
// Sample use:
//
//	import "token"
//	import "scanner"
//
//	func tokenize(src []byte) {
//		var s scanner.Scanner;
//		s.Init(src, nil /* no error handler */, false /* ignore comments */);
//		for {
//			pos, tok, lit := s.Scan();
//			if tok == Scanner.EOF {
//				return;
//			}
//			println(pos, token.TokenString(tok), string(lit));
//		}
//	}
//
package scanner

import (
	"utf8";
	"unicode";
	"strconv";
	"token";
)

// An implementation of an ErrorHandler must be provided to the Scanner.
// If a syntax error is encountered, Error() is called with the exact
// token position (the byte position of the token in the source) and the
// error message.
//
type ErrorHandler interface {
	Error(pos int, msg string);
}

// A Scanner holds the scanner's internal state while processing
// a given text.  It can be allocated as part of another data
// structure but must be initialized via Init() before use.
// See also the package comment for a sample use.
//
type Scanner struct {
	// immutable state
	src []byte;  // source
	err ErrorHandler;  // error reporting
	scan_comments bool;  // if set, comments are reported as tokens

	// scanning state
	pos int;  // current reading position
	ch int;  // one char look-ahead
	chpos int;  // position of ch
}

func isLetter(ch int) bool {
	return
		'a' <= ch && ch <= 'z' ||
		'A' <= ch && ch <= 'Z' ||
		ch == '_' ||
		ch >= 0x80 && unicode.IsLetter(ch);
}

func digitVal(ch int) int {
	switch {
	case '0' <= ch && ch <= '9': return ch - '0';
	case 'a' <= ch && ch <= 'f': return ch - 'a' + 10;
	case 'A' <= ch && ch <= 'F': return ch - 'A' + 10;
	}
	return 16;  // larger than any legal digit val
}

// Read the next Unicode char into S.ch.
// S.ch < 0 means end-of-file.
func (S *Scanner) next() {
	if S.pos < len(S.src) {
		// assume ASCII
		r, w := int(S.src[S.pos]), 1;
		if r >= 0x80 {
			// not ASCII
			r, w = utf8.DecodeRune(S.src[S.pos : len(S.src)]);
		}
		S.ch = r;
		S.chpos = S.pos;
		S.pos += w;
	} else {
		S.ch = -1;  // eof
		S.chpos = len(S.src);
	}
}

// Init() prepares the scanner S to tokenize the text src. Calls to Scan()
// will use the error handler err if they encounter a syntax error. The boolean
// scan_comments specifies whether newline characters and comments should be
// recognized and returned by Scan as token.COMMENT. If scan_comments is false,
// they are treated as white space and ignored.
//
func (S *Scanner) Init(src []byte, err ErrorHandler, scan_comments bool) {
	S.src = src;
	S.err = err;
	S.scan_comments = scan_comments;
	S.next();
}

func charString(ch int) string {
	s := string(ch);
	switch ch {
	case '\a': s = `\a`;
	case '\b': s = `\b`;
	case '\f': s = `\f`;
	case '\n': s = `\n`;
	case '\r': s = `\r`;
	case '\t': s = `\t`;
	case '\v': s = `\v`;
	case '\\': s = `\\`;
	case '\'': s = `\'`;
	}
	return "'" + s + "' (U+" + strconv.Itob(ch, 16) + ")";
}

func (S *Scanner) error(pos int, msg string) {
	S.err.Error(pos, msg);
}

func (S *Scanner) expect(ch int) {
	if S.ch != ch {
		S.error(S.chpos, "expected " + charString(ch) + ", found " + charString(S.ch));
	}
	S.next();  // always make progress
}

func (S *Scanner) skipWhitespace() {
	for {
		switch S.ch {
		case '\t', '\r', ' ':
			// nothing to do
		case '\n':
			if S.scan_comments {
				return;
			}
		default:
			return;
		}
		S.next();
	}
	panic("UNREACHABLE");
}

func (S *Scanner) scanComment() []byte {
	// first '/' already consumed
	pos := S.chpos - 1;

	if S.ch == '/' {
		//-style comment
		for S.ch >= 0 {
			S.next();
			if S.ch == '\n' {
				// '\n' terminates comment but we do not include
				// it in the comment (otherwise we don't see the
				// start of a newline in skipWhitespace()).
				return S.src[pos : S.chpos];
			}
		}

	} else {
		/*-style comment */
		S.expect('*');
		for S.ch >= 0 {
			ch := S.ch;
			S.next();
			if ch == '*' && S.ch == '/' {
				S.next();
				return S.src[pos : S.chpos];
			}
		}
	}

	S.error(pos, "comment not terminated");
	return S.src[pos : S.chpos];
}

func (S *Scanner) scanIdentifier() (tok int, lit []byte) {
	pos := S.chpos;
	for isLetter(S.ch) || digitVal(S.ch) < 10 {
		S.next();
	}
	lit = S.src[pos : S.chpos];
	return token.Lookup(lit), lit;
}

func (S *Scanner) scanMantissa(base int) {
	for digitVal(S.ch) < base {
		S.next();
	}
}

func (S *Scanner) scanNumber(seen_decimal_point bool) (tok int, lit []byte) {
	pos := S.chpos;
	tok = token.INT;

	if seen_decimal_point {
		tok = token.FLOAT;
		pos--;  // '.' is one byte
		S.scanMantissa(10);
		goto exponent;
	}

	if S.ch == '0' {
		// int or float
		S.next();
		if S.ch == 'x' || S.ch == 'X' {
			// hexadecimal int
			S.next();
			S.scanMantissa(16);
		} else {
			// octal int or float
			S.scanMantissa(8);
			if digitVal(S.ch) < 10 || S.ch == '.' || S.ch == 'e' || S.ch == 'E' {
				// float
				tok = token.FLOAT;
				goto mantissa;
			}
			// octal int
		}
		goto exit;
	}

mantissa:
	// decimal int or float
	S.scanMantissa(10);

	if S.ch == '.' {
		// float
		tok = token.FLOAT;
		S.next();
		S.scanMantissa(10)
	}

exponent:
	if S.ch == 'e' || S.ch == 'E' {
		// float
		tok = token.FLOAT;
		S.next();
		if S.ch == '-' || S.ch == '+' {
			S.next();
		}
		S.scanMantissa(10);
	}

exit:
	return tok, S.src[pos : S.chpos];
}

func (S *Scanner) scanDigits(n int, base int) {
	for digitVal(S.ch) < base {
		S.next();
		n--;
	}
	if n > 0 {
		S.error(S.chpos, "illegal char escape");
	}
}

func (S *Scanner) scanEscape(quote int) {
	ch := S.ch;
	pos := S.chpos;
	S.next();
	switch ch {
	case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', quote:
		// nothing to do
	case '0', '1', '2', '3', '4', '5', '6', '7':
		S.scanDigits(3 - 1, 8);  // 1 char read already
	case 'x':
		S.scanDigits(2, 16);
	case 'u':
		S.scanDigits(4, 16);
	case 'U':
		S.scanDigits(8, 16);
	default:
		S.error(pos, "illegal char escape");
	}
}

func (S *Scanner) scanChar() []byte {
	// '\'' already consumed

	pos := S.chpos - 1;
	ch := S.ch;
	S.next();
	if ch == '\\' {
		S.scanEscape('\'');
	}

	S.expect('\'');
	return S.src[pos : S.chpos];
}

func (S *Scanner) scanString() []byte {
	// '"' already consumed

	pos := S.chpos - 1;
	for S.ch != '"' {
		ch := S.ch;
		S.next();
		if ch == '\n' || ch < 0 {
			S.error(pos, "string not terminated");
			break;
		}
		if ch == '\\' {
			S.scanEscape('"');
		}
	}

	S.next();
	return S.src[pos : S.chpos];
}

func (S *Scanner) scanRawString() []byte {
	// '`' already consumed

	pos := S.chpos - 1;
	for S.ch != '`' {
		ch := S.ch;
		S.next();
		if ch == '\n' || ch < 0 {
			S.error(pos, "string not terminated");
			break;
		}
	}

	S.next();
	return S.src[pos : S.chpos];
}

// Helper functions for scanning multi-byte tokens such as >> += >>= .
// Different routines recognize different length tok_i based on matches
// of ch_i. If a token ends in '=', the result is tok1 or tok3
// respectively. Otherwise, the result is tok0 if there was no other
// matching character, or tok2 if the matching character was ch2.

func (S *Scanner) switch2(tok0, tok1 int) int {
	if S.ch == '=' {
		S.next();
		return tok1;
	}
	return tok0;
}

func (S *Scanner) switch3(tok0, tok1, ch2, tok2 int) int {
	if S.ch == '=' {
		S.next();
		return tok1;
	}
	if S.ch == ch2 {
		S.next();
		return tok2;
	}
	return tok0;
}

func (S *Scanner) switch4(tok0, tok1, ch2, tok2, tok3 int) int {
	if S.ch == '=' {
		S.next();
		return tok1;
	}
	if S.ch == ch2 {
		S.next();
		if S.ch == '=' {
			S.next();
			return tok3;
		}
		return tok2;
	}
	return tok0;
}

// Scan() scans the next token and returns the token byte position in the
// source, its token value, and the corresponding literal text if the token
// is an identifier, basic type literal (token.IsLiteral(tok) == true), or
// comment.
//
func (S *Scanner) Scan() (pos, tok int, lit []byte) {
scan_again:
	S.skipWhitespace();

	pos, tok = S.chpos, token.ILLEGAL;

	switch ch := S.ch; {
	case isLetter(ch):
		tok, lit = S.scanIdentifier();
	case digitVal(ch) < 10:
		tok, lit = S.scanNumber(false);
	default:
		S.next();  // always make progress
		switch ch {
		case -1  : tok = token.EOF;
		case '\n': tok, lit = token.COMMENT, []byte{'\n'};
		case '"' : tok, lit = token.STRING, S.scanString();
		case '\'': tok, lit = token.CHAR, S.scanChar();
		case '`' : tok, lit = token.STRING, S.scanRawString();
		case ':' : tok = S.switch2(token.COLON, token.DEFINE);
		case '.' :
			if digitVal(S.ch) < 10 {
				tok, lit = S.scanNumber(true);
			} else if S.ch == '.' {
				S.next();
				if S.ch == '.' {
					S.next();
					tok = token.ELLIPSIS;
				}
			} else {
				tok = token.PERIOD;
			}
		case ',': tok = token.COMMA;
		case ';': tok = token.SEMICOLON;
		case '(': tok = token.LPAREN;
		case ')': tok = token.RPAREN;
		case '[': tok = token.LBRACK;
		case ']': tok = token.RBRACK;
		case '{': tok = token.LBRACE;
		case '}': tok = token.RBRACE;
		case '+': tok = S.switch3(token.ADD, token.ADD_ASSIGN, '+', token.INC);
		case '-': tok = S.switch3(token.SUB, token.SUB_ASSIGN, '-', token.DEC);
		case '*': tok = S.switch2(token.MUL, token.MUL_ASSIGN);
		case '/':
			if S.ch == '/' || S.ch == '*' {
				tok, lit = token.COMMENT, S.scanComment();
				if !S.scan_comments {
					goto scan_again;
				}
			} else {
				tok = S.switch2(token.QUO, token.QUO_ASSIGN);
			}
		case '%': tok = S.switch2(token.REM, token.REM_ASSIGN);
		case '^': tok = S.switch2(token.XOR, token.XOR_ASSIGN);
		case '<':
			if S.ch == '-' {
				S.next();
				tok = token.ARROW;
			} else {
				tok = S.switch4(token.LSS, token.LEQ, '<', token.SHL, token.SHL_ASSIGN);
			}
		case '>': tok = S.switch4(token.GTR, token.GEQ, '>', token.SHR, token.SHR_ASSIGN);
		case '=': tok = S.switch2(token.ASSIGN, token.EQL);
		case '!': tok = S.switch2(token.NOT, token.NEQ);
		case '&': tok = S.switch3(token.AND, token.AND_ASSIGN, '&', token.LAND);
		case '|': tok = S.switch3(token.OR, token.OR_ASSIGN, '|', token.LOR);
		default: S.error(pos, "illegal character " + charString(ch));
		}
	}

	return pos, tok, lit;
}
<|endoftext|>


<commit_before>package gform

import (
    "unsafe"
    "w32"
    "w32/user32"
)

type Form struct {
    ControlBase

    isDialog bool
    isDragMove bool

    onClose EventManager
}

func NewForm(parent Controller) *Form {
    f := new(Form)
    f.init(parent)

    f.SetFont(DefaultFont)
    f.SetCaption("Form")

    return f
}

func (this *Form) init(parent Controller) {
    RegClassOnlyOnce("gform_Form")

    this.isForm = true
    this.isDialog = false
    this.isDragMove = false
    this.hwnd = CreateWindow("gform_Form", parent, w32.WS_EX_CLIENTEDGE, w32.WS_OVERLAPPEDWINDOW)
    this.ControlBase.init(parent)

    RegMsgHandler(this)
}

// Events
func (this *Form) OnClose() *EventManager {
    return &this.onClose
}

// Public methods
func (this *Form) Center() {
    sWidth := user32.GetSystemMetrics(w32.SM_CXFULLSCREEN)
    sHeight := user32.GetSystemMetrics(w32.SM_CYFULLSCREEN)

    if sWidth != 0 && sHeight != 0 {
        w, h := this.Size()
        this.SetPos((sWidth/2)-(w/2), (sHeight/2)-(h/2))
    }
}

// IconType: 1 - ICON_BIG; 0 - ICON_SMALL
func (this *Form) SetIcon(iconType int, icon *Icon) {
    if iconType > 1 {
        panic("IconType is invalid")
    }

    user32.SendMessage(this.hwnd, w32.WM_SETICON, uintptr(iconType), uintptr(icon.Handle()))
}

func (this *Form) SetMaxButtonEnabled(b bool) {
    ToggleStyle(this.hwnd, b, w32.WS_MAXIMIZEBOX)
}

func (this *Form) SetMinButtonEnabled(b bool) {
    ToggleStyle(this.hwnd, b, w32.WS_MINIMIZEBOX)
}

func (this *Form) SetSizable(b bool) {
    ToggleStyle(this.hwnd, b, w32.WS_THICKFRAME)
}

func (this *Form) SetDragMove(b bool) {
    this.isDragMove = b
}

func (this *Form) WndProc(msg uint, wparam, lparam uintptr) uintptr {
    switch msg {
    case w32.WM_LBUTTONDOWN:
        if this.isDragMove {
            user32.ReleaseCapture()
            user32.SendMessage(this.hwnd, w32.WM_NCLBUTTONDOWN, w32.HTCAPTION, 0)
        }
    case w32.WM_NOTIFY: //Reflect
        nm := (*w32.NMHDR)(unsafe.Pointer(lparam))
        if msgHandler := GetMsgHandler(nm.HwndFrom); msgHandler != nil {
            return msgHandler.WndProc(msg, wparam, lparam)
        }
    case w32.WM_COMMAND: //Reflect
        if lparam != 0 { //Control
            h := w32.HWND(lparam)
            if msgHandler := GetMsgHandler(h); msgHandler != nil {
                return msgHandler.WndProc(msg, wparam, lparam)
            }
        }
    case w32.WM_CLOSE:
        this.onClose.Fire(NewEventArg(this, nil))
        user32.DestroyWindow(this.hwnd)
    case w32.WM_DESTROY:
        user32.PostQuitMessage(0)
    }

    return user32.DefWindowProc(this.hwnd, msg, wparam, lparam)
}
<commit_msg>Rename "SetXXXEnabled" to "EnableXXX".<commit_after>package gform

import (
    "unsafe"
    "w32"
    "w32/user32"
)

type Form struct {
    ControlBase

    isDialog   bool
    isDragMove bool

    onClose EventManager
}

func NewForm(parent Controller) *Form {
    f := new(Form)
    f.init(parent)

    f.SetFont(DefaultFont)
    f.SetCaption("Form")

    return f
}

func (this *Form) init(parent Controller) {
    RegClassOnlyOnce("gform_Form")

    this.isForm = true
    this.isDialog = false
    this.isDragMove = false
    this.hwnd = CreateWindow("gform_Form", parent, w32.WS_EX_CLIENTEDGE, w32.WS_OVERLAPPEDWINDOW)
    this.ControlBase.init(parent)

    RegMsgHandler(this)
}

// Events
func (this *Form) OnClose() *EventManager {
    return &this.onClose
}

// Public methods
func (this *Form) Center() {
    sWidth := user32.GetSystemMetrics(w32.SM_CXFULLSCREEN)
    sHeight := user32.GetSystemMetrics(w32.SM_CYFULLSCREEN)

    if sWidth != 0 && sHeight != 0 {
        w, h := this.Size()
        this.SetPos((sWidth/2)-(w/2), (sHeight/2)-(h/2))
    }
}

// IconType: 1 - ICON_BIG; 0 - ICON_SMALL
func (this *Form) SetIcon(iconType int, icon *Icon) {
    if iconType > 1 {
        panic("IconType is invalid")
    }

    user32.SendMessage(this.hwnd, w32.WM_SETICON, uintptr(iconType), uintptr(icon.Handle()))
}

func (this *Form) EnableMaxButton(b bool) {
    ToggleStyle(this.hwnd, b, w32.WS_MAXIMIZEBOX)
}

func (this *Form) EnableMinButton(b bool) {
    ToggleStyle(this.hwnd, b, w32.WS_MINIMIZEBOX)
}

func (this *Form) SetSizable(b bool) {
    ToggleStyle(this.hwnd, b, w32.WS_THICKFRAME)
}

func (this *Form) SetDragMove(b bool) {
    this.isDragMove = b
}

func (this *Form) WndProc(msg uint, wparam, lparam uintptr) uintptr {
    switch msg {
    case w32.WM_LBUTTONDOWN:
        if this.isDragMove {
            user32.ReleaseCapture()
            user32.SendMessage(this.hwnd, w32.WM_NCLBUTTONDOWN, w32.HTCAPTION, 0)
        }
    case w32.WM_NOTIFY: //Reflect
        nm := (*w32.NMHDR)(unsafe.Pointer(lparam))
        if msgHandler := GetMsgHandler(nm.HwndFrom); msgHandler != nil {
            return msgHandler.WndProc(msg, wparam, lparam)
        }
    case w32.WM_COMMAND: //Reflect
        if lparam != 0 { //Control
            h := w32.HWND(lparam)
            if msgHandler := GetMsgHandler(h); msgHandler != nil {
                return msgHandler.WndProc(msg, wparam, lparam)
            }
        }
    case w32.WM_CLOSE:
        this.onClose.Fire(NewEventArg(this, nil))
        user32.DestroyWindow(this.hwnd)
    case w32.WM_DESTROY:
        user32.PostQuitMessage(0)
    }

    return user32.DefWindowProc(this.hwnd, msg, wparam, lparam)
}
<|endoftext|>


<commit_before><commit_msg>closing conn<commit_after><|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"os"

	"dfss/dfssc/sign"
	"github.com/spf13/cobra"
)

var signCmd = &cobra.Command{
	Use:   "sign <c>",
	Short: "sign contract from file c",
	Run: func(cmd *cobra.Command, args []string) {
		if len(args) != 1 {
			_ = cmd.Usage()
			os.Exit(1)
		}

		filename := args[0]
		fmt.Println("You are going to sign the following contract:")
		showContract(cmd, args)

		contract := getContract(filename)
		if contract == nil {
			os.Exit(1)
		}

		var passphrase string
		_ = readPassword(&passphrase, false)

		// Preparation
		manager, err := sign.NewSignatureManager(passphrase, contract)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(2)
		}

		manager.OnSignerStatusUpdate = signFeedbackFn
		err = manager.ConnectToPeers()
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(3)
		}

		// Confirmation
		var ready string
		readStringParam("Do you REALLY want to sign "+contract.File.Name+"? Type 'yes' to confirm", "", &ready)
		if ready != "yes" {
			os.Exit(4)
		}

		// Ignition
		fmt.Println("Waiting for other signers to be ready...")
		signatureUUID, err := manager.SendReadySign()
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(5)
		}

		// TODO Warning, integration tests are checking Stdout
		fmt.Println("Everybody is ready, starting the signature", signatureUUID)

		// Signature
		manager.OnProgressUpdate = signProgressFn
		err = manager.Sign()
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(5)
		}

		// Persist evidencies, if any
		err = manager.PersistSignaturesToFile()
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(5)
		}

		fmt.Println("Signature complete! See .proof file for evidences.")
	},
}

func signFeedbackFn(mail string, status sign.SignerStatus, data string) {
	if status == sign.StatusConnecting {
		fmt.Println("- Trying to connect with", mail, "/", data)
	} else if status == sign.StatusConnected {
		fmt.Println("  Successfully connected!", "[", data, "]")
	}
}

func signProgressFn(current int, max int) {}
<commit_msg>[c] Show more flow info during signature<commit_after>package cmd

import (
	"fmt"
	"os"

	"dfss/dfssc/sign"
	"github.com/spf13/cobra"
)

var signCmd = &cobra.Command{
	Use:   "sign <c>",
	Short: "sign contract from file c",
	Run: func(cmd *cobra.Command, args []string) {
		if len(args) != 1 {
			_ = cmd.Usage()
			os.Exit(1)
		}

		filename := args[0]
		fmt.Println("You are going to sign the following contract:")
		showContract(cmd, args)

		contract := getContract(filename)
		if contract == nil {
			os.Exit(1)
		}

		var passphrase string
		_ = readPassword(&passphrase, false)

		// Preparation
		manager, err := sign.NewSignatureManager(passphrase, contract)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(2)
		}

		fmt.Println("Waiting for peers...")
		manager.OnSignerStatusUpdate = signFeedbackFn
		err = manager.ConnectToPeers()
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(3)
		}

		// Confirmation
		var ready string
		readStringParam("Do you REALLY want to sign "+contract.File.Name+"? Type 'yes' to confirm", "", &ready)
		if ready != "yes" {
			fmt.Println("Signature aborted!")
			os.Exit(4)
		}

		// Ignition
		fmt.Println("Waiting for other signers to be ready...")
		signatureUUID, err := manager.SendReadySign()
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(5)
		}

		// TODO Warning, integration tests are checking Stdout
		fmt.Println("Everybody is ready, starting the signature", signatureUUID)

		// Signature
		manager.OnProgressUpdate = signProgressFn
		err = manager.Sign()
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(5)
		}

		// Persist evidencies, if any
		err = manager.PersistSignaturesToFile()
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(5)
		}

		fmt.Println("Signature complete! See .proof file for evidences.")
	},
}

func signFeedbackFn(mail string, status sign.SignerStatus, data string) {
	if status == sign.StatusConnecting {
		fmt.Println("- Trying to connect with", mail, "/", data)
	} else if status == sign.StatusConnected {
		fmt.Println("  Successfully connected!", "[", data, "]")
	}
}

func signProgressFn(current int, max int) {}
<|endoftext|>


<commit_before>package sej

import (
	"io"
	"os"
	"sync"

	"gopkg.in/fsnotify.v1"
)

type watchedJournalDir struct {
	dir     *journalDir
	watcher *fsnotify.Watcher
	err     error
	mu      sync.RWMutex
	wg      sync.WaitGroup
	changed chan bool
}

func openWatchedJournalDir(dir string, changed chan bool) (*watchedJournalDir, error) {
	journalDir, err := openJournalDir(dir)
	if err != nil {
		return nil, err
	}
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, err
	}
	if err := watcher.Add(dir); err != nil {
		watcher.Close()
		return nil, err
	}
	d := &watchedJournalDir{
		dir:     journalDir,
		watcher: watcher,
		changed: changed,
	}
	d.wg.Add(2)
	go d.watchEvent()
	go d.watchError()
	return d, nil
}

func (d *watchedJournalDir) find(offset uint64) (*journalFile, error) {
	d.mu.RLock()
	defer d.mu.RUnlock()
	if d.err != nil {
		return nil, d.err
	}
	return d.dir.find(offset)
}

func (d *watchedJournalDir) isLast(f *journalFile) bool {
	d.mu.RLock()
	defer d.mu.RUnlock()
	return d.dir.isLast(f)
}

func (d *watchedJournalDir) watchEvent() {
	defer d.wg.Done()
	for event := range d.watcher.Events {
		if event.Op&(fsnotify.Create|fsnotify.Remove) > 0 {
			d.reload()
			select {
			case d.changed <- true:
			default:
			}
		}
	}
}

func (d *watchedJournalDir) watchError() {
	defer d.wg.Done()
	for err := range d.watcher.Errors {
		d.mu.Lock()
		d.err = err
		d.mu.Unlock()
	}
}

func (d *watchedJournalDir) reload() {
	d.mu.Lock()
	defer d.mu.Unlock()
	journalDir, err := openJournalDir(d.dir.path)
	if err != nil {
		d.err = err
	}
	d.dir = journalDir
}

func (d *watchedJournalDir) close() error {
	d.watcher.Remove(d.dir.path)
	d.watcher.Close()
	d.wg.Wait()
	return nil
}

type watchedFile struct {
	file     *os.File
	watcher  *fsnotify.Watcher
	modified bool
	err      error
	mu       sync.RWMutex
	wg       sync.WaitGroup
	changed  chan bool
}

func openWatchedFile(name string, changed chan bool) (*watchedFile, error) {
	file, err := os.Open(name)
	if err != nil {
		return nil, err
	}
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, err
	}
	if err := watcher.Add(name); err != nil {
		watcher.Close()
		return nil, err
	}
	f := &watchedFile{
		file:    file,
		watcher: watcher,
		changed: changed,
	}
	f.wg.Add(2)
	go f.watchEvent()
	go f.watchError()
	return f, nil
}

func (f *watchedFile) watchEvent() {
	defer f.wg.Done()
	for event := range f.watcher.Events {
		if event.Op&(fsnotify.Write) > 0 {
			f.modified = true
			select {
			case f.changed <- true:
			default:
			}
		}
	}
}

func (f *watchedFile) watchError() {
	defer f.wg.Done()
	for err := range f.watcher.Errors {
		f.mu.Lock()
		f.err = err
		f.mu.Unlock()
	}
}

func (f *watchedFile) reopen() error {
	oldStat, err := f.file.Stat()
	if err != nil {
		return err
	}
	oldSize := oldStat.Size()
	fileName := f.file.Name()
	newFile, err := os.Open(fileName)
	if err != nil {
		return err
	}
	if _, err := newFile.Seek(oldSize, os.SEEK_SET); err != nil {
		newFile.Close()
		return err
	}
	if err := f.file.Close(); err != nil {
		return err
	}
	f.file = newFile
	f.modified = false
	return nil
}

func (f *watchedFile) Read(p []byte) (n int, err error) {
	f.mu.Lock()
	defer f.mu.Unlock()
	if f.err != nil {
		return 0, f.err
	}
	n, err = f.file.Read(p)
	if err == io.EOF && f.modified {
		if nil != f.reopen() {
			return n, err
		}
		return f.file.Read(p)
	}
	return n, err
}

func (f *watchedFile) Close() error {
	f.watcher.Remove(f.file.Name())
	f.watcher.Close()
	f.wg.Wait()
	return nil
}
<commit_msg>lazy loading for directory too<commit_after>package sej

import (
	"io"
	"os"
	"sync"

	"gopkg.in/fsnotify.v1"
)

type watchedJournalDir struct {
	dir      *journalDir
	watcher  *fsnotify.Watcher
	modified bool
	err      error
	mu       sync.RWMutex
	wg       sync.WaitGroup
	changed  chan bool
}

func openWatchedJournalDir(dir string, changed chan bool) (*watchedJournalDir, error) {
	dirFile, err := openOrCreateDir(dir)
	if err != nil {
		return nil, err
	}
	dirFile.Close()
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, err
	}
	if err := watcher.Add(dir); err != nil {
		watcher.Close()
		return nil, err
	}
	d := &watchedJournalDir{
		watcher: watcher,
		changed: changed,
	}
	d.wg.Add(2)
	go d.watchEvent()
	go d.watchError()
	d.dir, err = openJournalDir(dir)
	if err != nil {
		watcher.Close()
		return nil, err
	}
	return d, nil
}

func (d *watchedJournalDir) find(offset uint64) (*journalFile, error) {
	d.mu.RLock()
	defer d.mu.RUnlock()
	if d.err != nil {
		return nil, d.err
	}
	if err := d.reload(); err != nil {
		d.err = err
		return nil, err
	}
	return d.dir.find(offset)
}

func (d *watchedJournalDir) isLast(f *journalFile) bool {
	d.mu.RLock()
	defer d.mu.RUnlock()
	if err := d.reload(); err != nil {
		d.err = err
		return false
	}
	return d.dir.isLast(f)
}

func (d *watchedJournalDir) watchEvent() {
	defer d.wg.Done()
	for event := range d.watcher.Events {
		if event.Op&(fsnotify.Create|fsnotify.Remove) > 0 {
			d.mu.Lock()
			d.modified = true
			d.mu.Unlock()
			select {
			case d.changed <- true:
			default:
			}
		}
	}
}

func (d *watchedJournalDir) watchError() {
	defer d.wg.Done()
	for err := range d.watcher.Errors {
		d.mu.Lock()
		d.err = err
		d.mu.Unlock()
	}
}

func (d *watchedJournalDir) reload() error {
	if !d.modified {
		return nil
	}
	journalDir, err := openJournalDir(d.dir.path)
	if err != nil {
		return err
	}
	d.dir = journalDir
	d.modified = false
	return nil
}

func (d *watchedJournalDir) close() error {
	d.watcher.Remove(d.dir.path)
	d.watcher.Close()
	d.wg.Wait()
	return nil
}

type watchedFile struct {
	file     *os.File
	watcher  *fsnotify.Watcher
	modified bool
	err      error
	mu       sync.RWMutex
	wg       sync.WaitGroup
	changed  chan bool
}

func openWatchedFile(name string, changed chan bool) (*watchedFile, error) {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, err
	}
	if err := watcher.Add(name); err != nil {
		watcher.Close()
		return nil, err
	}
	f := &watchedFile{
		watcher: watcher,
		changed: changed,
	}
	f.wg.Add(2)
	go f.watchEvent()
	go f.watchError()
	f.file, err = os.Open(name)
	if err != nil {
		watcher.Close()
		return nil, err
	}
	return f, nil
}

func (f *watchedFile) watchEvent() {
	defer f.wg.Done()
	for event := range f.watcher.Events {
		if event.Op&(fsnotify.Write) > 0 {
			f.modified = true
			select {
			case f.changed <- true:
			default:
			}
		}
	}
}

func (f *watchedFile) watchError() {
	defer f.wg.Done()
	for err := range f.watcher.Errors {
		f.mu.Lock()
		f.err = err
		f.mu.Unlock()
	}
}

func (f *watchedFile) reopen() error {
	oldStat, err := f.file.Stat()
	if err != nil {
		return err
	}
	oldSize := oldStat.Size()
	fileName := f.file.Name()
	newFile, err := os.Open(fileName)
	if err != nil {
		return err
	}
	if _, err := newFile.Seek(oldSize, os.SEEK_SET); err != nil {
		newFile.Close()
		return err
	}
	if err := f.file.Close(); err != nil {
		return err
	}
	f.file = newFile
	f.modified = false
	return nil
}

func (f *watchedFile) Read(p []byte) (n int, err error) {
	f.mu.Lock()
	defer f.mu.Unlock()
	if f.err != nil {
		return 0, f.err
	}
	n, err = f.file.Read(p)
	if err == io.EOF && f.modified {
		if nil != f.reopen() {
			return n, err
		}
		return f.file.Read(p)
	}
	return n, err
}

func (f *watchedFile) Close() error {
	f.watcher.Remove(f.file.Name())
	f.watcher.Close()
	f.wg.Wait()
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"code.google.com/p/getopt"
	"fmt"
	"io"
	"os"
	"regexp"
	"unicode/utf8"
)

// words are define as any space delimited substring
func count_words(str string) int {
	word := regexp.MustCompile("\\S+")
	s := word.FindAllString(str, -1)
	return len(s)
}

func count_chars(str string) int {
	return utf8.RuneCountInString(str)
}

func main() {
	/* c = bytes
	 * m = chars
	 * l = lines
	 * w = words
	 */
	var total_c, total_m, total_l, total_w int = 0, 0, 0, 0

	isBytes := getopt.Bool('c', "count bytes")
	isChars := getopt.Bool('m', "count chars")
	isWords := getopt.Bool('w', "count words")
	isLines := getopt.Bool('l', "count lines")

	getopt.Parse()

	// If no parameters are given default to showing lines, words and bytes
	if !*isBytes && !*isChars && !*isWords && !*isLines {
		*isBytes = true
		*isWords = true
		*isLines = true
	}

	nargs := getopt.NArgs()

	/* Loop through the file reading the statistics */
	for _, file := range getopt.Args() {
		f, err := os.Open(file)
		if err != nil {
			os.Exit(1)
		}

		var c, m, l, w int = 0, 0, 0, 0
		var last_line bool = false

		nr := bufio.NewReader(f)
		for {
			line, err := nr.ReadString('\n')
			if err == io.EOF {
				if len(line) == 0 {
					break
				}
				last_line = true
			} else if err != nil {
				os.Exit(-1)
			}
			l++
			if *isBytes {
				c += len(line)
				total_c += len(line)
			}
			if *isChars {
				m += count_chars(line)
			}
			if *isWords {
				w += count_words(line)
			}
			if last_line {
				break
			}
		}

		/* Print the outcome */
		if *isLines {
			fmt.Printf("%d ", l)
		}
		if *isWords {
			fmt.Printf("%d ", w)
		}
		if *isChars {
			fmt.Printf("%d ", m)
		} else if *isBytes {
			fmt.Printf("%d ", c)
		}
		fmt.Println(file)

		/* Update total counts */
		if nargs > 1 {
			total_c += c
			total_m += m
			total_w += w
			total_l += l
		}
	}

	if nargs > 1 {
		/* Print the outcome */
		if *isLines {
			fmt.Printf("%d ", total_l)
		}
		if *isWords {
			fmt.Printf("%d ", total_w)
		}
		if *isChars {
			fmt.Printf("%d ", total_m)
		} else if *isBytes {
			fmt.Printf("%d ", total_c)
		}
		fmt.Println("total")
	}
}
<commit_msg>Add STDIN handling to wc<commit_after>package main

import (
	"bufio"
	"code.google.com/p/getopt"
	"fmt"
	"io"
	"os"
	"regexp"
	"unicode/utf8"
)

// words are define as any space delimited substring
func count_words(str string) int {
	word := regexp.MustCompile("\\S+")
	s := word.FindAllString(str, -1)
	return len(s)
}

func count_chars(str string) int {
	return utf8.RuneCountInString(str)
}

func main() {
	/* c = bytes
	 * m = chars
	 * l = lines
	 * w = words
	 */
	var total_c, total_m, total_l, total_w int = 0, 0, 0, 0
	var stdin_only bool = false

	isBytes := getopt.Bool('c', "count bytes")
	isChars := getopt.Bool('m', "count chars")
	isWords := getopt.Bool('w', "count words")
	isLines := getopt.Bool('l', "count lines")

	getopt.Parse()

	// If no parameters are given default to showing lines, words and bytes
	if !*isBytes && !*isChars && !*isWords && !*isLines {
		*isBytes = true
		*isWords = true
		*isLines = true
	}

	args := getopt.Args()
	nargs := getopt.NArgs()

	/* Add emtpy file to list if its empty */
	if nargs == 0 {
		args = append(args, "")
		stdin_only = true
	}

	/* Loop through the file reading the statistics */
	for _, file := range args {
		var f *os.File = os.Stdin
		if file != "-" && file != "" && !stdin_only {
			var err error
			f, err = os.Open(file)
			if err != nil {
				os.Exit(1)
			}
		}

		var c, m, l, w int = 0, 0, 0, 0
		var last_line bool = false

		nr := bufio.NewReader(f)
		for {
			line, err := nr.ReadString('\n')
			if err == io.EOF {
				if len(line) == 0 {
					break
				}
				last_line = true
			} else if err != nil {
				os.Exit(-1)
			}
			l++
			if *isBytes {
				c += len(line)
				total_c += len(line)
			}
			if *isChars {
				m += count_chars(line)
			}
			if *isWords {
				w += count_words(line)
			}
			if last_line {
				break
			}
		}

		/* Print the outcome */
		if *isLines {
			fmt.Printf("%d ", l)
		}
		if *isWords {
			fmt.Printf("%d ", w)
		}
		if *isChars {
			fmt.Printf("%d ", m)
		} else if *isBytes {
			fmt.Printf("%d ", c)
		}
		fmt.Println(file)

		/* Update total counts */
		if nargs > 1 {
			total_c += c
			total_m += m
			total_w += w
			total_l += l
		}
	}

	if nargs > 1 {
		/* Print the outcome */
		if *isLines {
			fmt.Printf("%d ", total_l)
		}
		if *isWords {
			fmt.Printf("%d ", total_w)
		}
		if *isChars {
			fmt.Printf("%d ", total_m)
		} else if *isBytes {
			fmt.Printf("%d ", total_c)
		}
		fmt.Println("total")
	}
}
<|endoftext|>


<commit_before>package jiracli

import (
	"fmt"
	"strings"

	"github.com/coryb/figtree"
	"github.com/coryb/oreo"

	jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
	"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata"
	kingpin "gopkg.in/alecthomas/kingpin.v2"
)

type TransitionOptions struct {
	GlobalOptions `yaml:",inline" json:",inline" figtree:",inline"`
	Overrides     map[string]string `yaml:"overrides,omitempty" json:"overrides,omitempty"`
	Transition    string            `yaml:"transition,omitempty" json:"transition,omitempty"`
	Issue         string            `yaml:"issue,omitempty" json:"issue,omitempty"`
	Resolution    string            `yaml:"resolution,omitempty" json:"resolution,omitempty"`
}

func CmdTransitionRegistry(fig *figtree.FigTree, o *oreo.Client, transition string) *CommandRegistryEntry {
	opts := TransitionOptions{
		GlobalOptions: GlobalOptions{
			Template: figtree.NewStringOption("transition"),
		},
		Overrides: map[string]string{},
	}

	help := "Transition issue to given state"
	if transition == "" {
		help = fmt.Sprintf("Transition issue to %s state", transition)
		opts.SkipEditing = figtree.NewBoolOption(true)
	}

	return &CommandRegistryEntry{
		help,
		func() error {
			return CmdTransition(o, &opts)
		},
		func(cmd *kingpin.CmdClause) error {
			LoadConfigs(cmd, fig, &opts)
			if opts.Transition == "" {
				opts.Transition = transition
			}
			return CmdTransitionUsage(cmd, &opts)
		},
	}
}

func CmdTransitionUsage(cmd *kingpin.CmdClause, opts *TransitionOptions) error {
	if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
		return err
	}
	BrowseUsage(cmd, &opts.GlobalOptions)
	TemplateUsage(cmd, &opts.GlobalOptions)
	cmd.Flag("noedit", "Disable opening the editor").SetValue(&opts.SkipEditing)
	cmd.Flag("comment", "Comment message for issue").Short('m').PreAction(func(ctx *kingpin.ParseContext) error {
		opts.Overrides["comment"] = flagValue(ctx, "comment")
		return nil
	}).String()
	cmd.Flag("override", "Set issue property").Short('o').StringMapVar(&opts.Overrides)
	if opts.Transition == "" {
		cmd.Arg("TRANSITION", "State to transition issue to").Required().StringVar(&opts.Transition)
	}
	cmd.Arg("ISSUE", "issue to transition").Required().StringVar(&opts.Issue)
	return nil
}

// CmdTransition will move state of the given issue to the given transtion
func CmdTransition(o *oreo.Client, opts *TransitionOptions) error {
	issueData, err := jira.GetIssue(o, opts.Endpoint.Value, opts.Issue, nil)
	if err != nil {
		return err
	}

	meta, err := jira.GetIssueTransitions(o, opts.Endpoint.Value, opts.Issue)
	if err != nil {
		return err
	}
	transMeta := meta.Transitions.Find(opts.Transition)

	if transMeta == nil {
		possible := []string{}
		for _, trans := range meta.Transitions {
			possible = append(possible, trans.Name)
		}

		if status, ok := issueData.Fields["status"].(map[string]interface{}); ok {
			if name, ok := status["name"].(string); ok {
				return fmt.Errorf("Invalid Transition %q from %q, Available: %s", opts.Transition, name, strings.Join(possible, ", "))
			}
		}
		return fmt.Errorf("No valid transition found matching %s", opts.Transition)
	}

	// need to default the Resolution, usually Fixed works but sometime need Done
	if opts.Resolution == "" {
		if resField, ok := transMeta.Fields["resolution"]; ok {
			for _, allowedValueRaw := range resField.AllowedValues {
				if allowedValue, ok := allowedValueRaw.(map[string]interface{}); ok {
					if allowedValue["name"] == "Fixed" {
						opts.Resolution = "Fixed"
					} else if allowedValue["name"] == "Done" {
						opts.Resolution = "Done"
					}
				}
			}
		}
	}
	opts.Overrides["resolution"] = opts.Resolution

	type templateInput struct {
		*jiradata.Issue `yaml:",inline"`
		// Yes, Meta and Transition are redundant, but this is for backwards compatibility
		// with old templates
		Meta       *jiradata.Transition `yaml:"meta,omitempty" json:"meta,omitemtpy"`
		Transition *jiradata.Transition `yaml:"transition,omitempty" json:"transition,omitempty"`
		Overrides  map[string]string    `yaml:"overrides,omitempty" json:"overrides,omitempty"`
	}

	issueUpdate := jiradata.IssueUpdate{}
	input := templateInput{
		Issue:      issueData,
		Meta:       transMeta,
		Transition: transMeta,
		Overrides:  opts.Overrides,
	}
	err = editLoop(&opts.GlobalOptions, &input, &issueUpdate, func() error {
		return jira.TransitionIssue(o, opts.Endpoint.Value, opts.Issue, &issueUpdate)
	})
	if err != nil {
		return err
	}
	fmt.Printf("OK %s %s/browse/%s\n", issueData.Key, opts.Endpoint.Value, issueData.Key)

	if opts.Browse.Value {
		return CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue})
	}
	return nil
}
<commit_msg>fix bogus logic error<commit_after>package jiracli

import (
	"fmt"
	"strings"

	"github.com/coryb/figtree"
	"github.com/coryb/oreo"

	jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
	"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata"
	kingpin "gopkg.in/alecthomas/kingpin.v2"
)

type TransitionOptions struct {
	GlobalOptions `yaml:",inline" json:",inline" figtree:",inline"`
	Overrides     map[string]string `yaml:"overrides,omitempty" json:"overrides,omitempty"`
	Transition    string            `yaml:"transition,omitempty" json:"transition,omitempty"`
	Issue         string            `yaml:"issue,omitempty" json:"issue,omitempty"`
	Resolution    string            `yaml:"resolution,omitempty" json:"resolution,omitempty"`
}

func CmdTransitionRegistry(fig *figtree.FigTree, o *oreo.Client, transition string) *CommandRegistryEntry {
	opts := TransitionOptions{
		GlobalOptions: GlobalOptions{
			Template: figtree.NewStringOption("transition"),
		},
		Overrides: map[string]string{},
	}

	help := "Transition issue to given state"
	if transition != "" {
		help = fmt.Sprintf("Transition issue to %s state", transition)
		opts.SkipEditing = figtree.NewBoolOption(true)
	}

	return &CommandRegistryEntry{
		help,
		func() error {
			return CmdTransition(o, &opts)
		},
		func(cmd *kingpin.CmdClause) error {
			LoadConfigs(cmd, fig, &opts)
			if opts.Transition == "" {
				opts.Transition = transition
			}
			return CmdTransitionUsage(cmd, &opts)
		},
	}
}

func CmdTransitionUsage(cmd *kingpin.CmdClause, opts *TransitionOptions) error {
	if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
		return err
	}
	BrowseUsage(cmd, &opts.GlobalOptions)
	TemplateUsage(cmd, &opts.GlobalOptions)
	cmd.Flag("noedit", "Disable opening the editor").SetValue(&opts.SkipEditing)
	cmd.Flag("comment", "Comment message for issue").Short('m').PreAction(func(ctx *kingpin.ParseContext) error {
		opts.Overrides["comment"] = flagValue(ctx, "comment")
		return nil
	}).String()
	cmd.Flag("override", "Set issue property").Short('o').StringMapVar(&opts.Overrides)
	if opts.Transition == "" {
		cmd.Arg("TRANSITION", "State to transition issue to").Required().StringVar(&opts.Transition)
	}
	cmd.Arg("ISSUE", "issue to transition").Required().StringVar(&opts.Issue)
	return nil
}

// CmdTransition will move state of the given issue to the given transtion
func CmdTransition(o *oreo.Client, opts *TransitionOptions) error {
	issueData, err := jira.GetIssue(o, opts.Endpoint.Value, opts.Issue, nil)
	if err != nil {
		return err
	}

	meta, err := jira.GetIssueTransitions(o, opts.Endpoint.Value, opts.Issue)
	if err != nil {
		return err
	}
	transMeta := meta.Transitions.Find(opts.Transition)

	if transMeta == nil {
		possible := []string{}
		for _, trans := range meta.Transitions {
			possible = append(possible, trans.Name)
		}

		if status, ok := issueData.Fields["status"].(map[string]interface{}); ok {
			if name, ok := status["name"].(string); ok {
				return fmt.Errorf("Invalid Transition %q from %q, Available: %s", opts.Transition, name, strings.Join(possible, ", "))
			}
		}
		return fmt.Errorf("No valid transition found matching %s", opts.Transition)
	}

	// need to default the Resolution, usually Fixed works but sometime need Done
	if opts.Resolution == "" {
		if resField, ok := transMeta.Fields["resolution"]; ok {
			for _, allowedValueRaw := range resField.AllowedValues {
				if allowedValue, ok := allowedValueRaw.(map[string]interface{}); ok {
					if allowedValue["name"] == "Fixed" {
						opts.Resolution = "Fixed"
					} else if allowedValue["name"] == "Done" {
						opts.Resolution = "Done"
					}
				}
			}
		}
	}
	opts.Overrides["resolution"] = opts.Resolution

	type templateInput struct {
		*jiradata.Issue `yaml:",inline"`
		// Yes, Meta and Transition are redundant, but this is for backwards compatibility
		// with old templates
		Meta       *jiradata.Transition `yaml:"meta,omitempty" json:"meta,omitemtpy"`
		Transition *jiradata.Transition `yaml:"transition,omitempty" json:"transition,omitempty"`
		Overrides  map[string]string    `yaml:"overrides,omitempty" json:"overrides,omitempty"`
	}

	issueUpdate := jiradata.IssueUpdate{}
	input := templateInput{
		Issue:      issueData,
		Meta:       transMeta,
		Transition: transMeta,
		Overrides:  opts.Overrides,
	}
	err = editLoop(&opts.GlobalOptions, &input, &issueUpdate, func() error {
		return jira.TransitionIssue(o, opts.Endpoint.Value, opts.Issue, &issueUpdate)
	})
	if err != nil {
		return err
	}
	fmt.Printf("OK %s %s/browse/%s\n", issueData.Key, opts.Endpoint.Value, issueData.Key)

	if opts.Browse.Value {
		return CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue})
	}
	return nil
}
<|endoftext|>