<commit_before>/*
Copyright 2017 Google Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package jsonnet

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"unsafe"

	"github.com/google/go-jsonnet/ast"
	"github.com/google/go-jsonnet/internal/program"
)

// An Importer imports data from a path.
// TODO(sbarzowski) caching of errors (may require breaking changes)
type Importer interface {
	// Import fetches data from a given path. It may be relative
	// to the file where we do the import. What "relative path"
	// means depends on the importer.
	//
	// It is required that:
	// a) for given (importedFrom, importedPath) the same
	//    (contents, foundAt) are returned on subsequent calls.
	// b) for given foundAt, the contents are always the same
	//
	// It is recommended that if there are multiple locations that
	// need to be probed (e.g. relative + multiple library paths)
	// then all results of all attempts will be cached separately,
	// both nonexistence and contents of existing ones.
	// FileImporter may serve as an example.
	//
	// IMPORTANT: The passed importedFrom might be "" (an empty string).
	// It means that the import is coming from an ad-hoc snippet, e.g.
	// code passed on the command line, read from stdin or passed as
	// a snippet to execute. Importer may have a "default" path to use
	// in such case or it may only allow absolute imports from such
	// "anonymous locations".
	//
	// Importing the same file multiple times must be a cheap operation
	// and shouldn't involve copying the whole file - the same buffer
	// should be returned.
	Import(importedFrom, importedPath string) (contents Contents, foundAt string, err error)
}

// Contents is a representation of imported data. It is a simple
// byte wrapper, which makes it easier to enforce the caching policy.
type Contents struct {
	data *[]byte
}

func (c Contents) String() string {
	// Construct string without copying underlying bytes.
	// NB: This only works because c.data is not modified.
	return *(*string)(unsafe.Pointer(c.data))
}

// Data returns content bytes
func (c Contents) Data() []byte {
	return *c.data
}

// MakeContents creates Contents from a string.
func MakeContents(s string) Contents {
	data := []byte(s)
	return Contents{
		data: &data,
	}
}

// MakeContentsRaw creates Contents from (possibly non-utf8) []byte data.
func MakeContentsRaw(bytes []byte) Contents {
	return Contents{
		data: &bytes,
	}
}

// importCache represents a cache of imported data.
//
// While the user-defined Importer implementations
// are required to cache file content, this cache
// is an additional layer of optimization that caches values
// (i.e. the result of executing the file content).
// It also verifies that the content pointer is the same for two foundAt values.
type importCache struct {
	foundAtVerification map[string]Contents
	astCache            map[string]ast.Node
	codeCache           map[string]potentialValue
	importer            Importer
}

// makeImportCache creates an importCache using an Importer.
func makeImportCache(importer Importer) *importCache {
	return &importCache{
		importer:            importer,
		foundAtVerification: make(map[string]Contents),
		astCache:            make(map[string]ast.Node),
		codeCache:           make(map[string]potentialValue),
	}
}

func (cache *importCache) flushValueCache() {
	cache.codeCache = make(map[string]potentialValue)
}

func (cache *importCache) importData(importedFrom, importedPath string) (contents Contents, foundAt string, err error) {
	contents, foundAt, err = cache.importer.Import(importedFrom, importedPath)
	if err != nil {
		return Contents{}, "", err
	}
	if cached, importedBefore := cache.foundAtVerification[foundAt]; importedBefore {
		if cached != contents {
			panic(fmt.Sprintf("importer problem: a different instance of Contents returned when importing %#v again", foundAt))
		}
	} else {
		cache.foundAtVerification[foundAt] = contents
	}
	return
}

func (cache *importCache) importAST(importedFrom, importedPath string) (ast.Node, string, error) {
	contents, foundAt, err := cache.importData(importedFrom, importedPath)
	if err != nil {
		return nil, "", err
	}
	if cachedNode, isCached := cache.astCache[foundAt]; isCached {
		return cachedNode, foundAt, nil
	}
	node, err := program.SnippetToAST(ast.DiagnosticFileName(foundAt), foundAt, contents.String())
	cache.astCache[foundAt] = node
	return node, foundAt, err
}

// ImportString imports a string, caches it and then returns it.
func (cache *importCache) importString(importedFrom, importedPath string, i *interpreter) (valueString, error) {
	data, _, err := cache.importData(importedFrom, importedPath)
	if err != nil {
		return nil, i.Error(err.Error())
	}
	return makeValueString(data.String()), nil
}

// ImportString imports an array of bytes, caches it and then returns it.
func (cache *importCache) importBinary(importedFrom, importedPath string, i *interpreter) (*valueArray, error) {
	data, _, err := cache.importData(importedFrom, importedPath)
	if err != nil {
		return nil, i.Error(err.Error())
	}
	bytes := data.Data()
	elements := make([]*cachedThunk, len(bytes))
	for i := range bytes {
		elements[i] = readyThunk(intToValue(int(bytes[i])))
	}
	return makeValueArray(elements), nil
}

func nodeToPV(i *interpreter, filename string, node ast.Node) *cachedThunk {
	env := makeInitialEnv(filename, i.baseStd)
	return &cachedThunk{
		env:     &env,
		body:    node,
		content: nil,
	}
}

func codeToPV(i *interpreter, filename string, code string) *cachedThunk {
	node, err := program.SnippetToAST(ast.DiagnosticFileName(filename), "", code)
	if err != nil {
		// TODO(sbarzowski) we should wrap (static) error here
		// within a RuntimeError. Because whether we get this error or not
		// actually depends on what happens in Runtime (whether import gets
		// evaluated).
		// The same thinking applies to external variables.
		return &cachedThunk{err: err}
	}
	return nodeToPV(i, filename, node)
}

// ImportCode imports code from a path.
func (cache *importCache) importCode(importedFrom, importedPath string, i *interpreter) (value, error) {
	node, foundAt, err := cache.importAST(importedFrom, importedPath)
	if err != nil {
		return nil, i.Error(err.Error())
	}
	var pv potentialValue
	if cachedPV, isCached := cache.codeCache[foundAt]; !isCached {
		// File hasn't been parsed and analyzed before, update the cache record.
		env := makeInitialEnv(foundAt, i.baseStd)
		pv = &cachedThunk{
			env:     &env,
			body:    node,
			content: nil,
		}
		cache.codeCache[foundAt] = pv
	} else {
		pv = cachedPV
	}
	return i.evaluatePV(pv)
}

// Concrete importers
// -------------------------------------

// FileImporter imports data from the filesystem.
type FileImporter struct {
	fsCache map[string]*fsCacheEntry
	JPaths  []string
}

type fsCacheEntry struct {
	contents Contents
	exists   bool
}

func (importer *FileImporter) tryPath(dir, importedPath string) (found bool, contents Contents, foundHere string, err error) {
	if importer.fsCache == nil {
		importer.fsCache = make(map[string]*fsCacheEntry)
	}
	var absPath string
	if path.IsAbs(importedPath) {
		absPath = importedPath
	} else {
		absPath = path.Join(dir, importedPath)
	}
	var entry *fsCacheEntry
	if cacheEntry, isCached := importer.fsCache[absPath]; isCached {
		entry = cacheEntry
	} else {
		contentBytes, err := ioutil.ReadFile(absPath)
		if err != nil {
			if os.IsNotExist(err) {
				entry = &fsCacheEntry{
					exists: false,
				}
			} else {
				return false, Contents{}, "", err
			}
		} else {
			entry = &fsCacheEntry{
				exists:   true,
				contents: MakeContentsRaw(contentBytes),
			}
		}
		importer.fsCache[absPath] = entry
	}
	return entry.exists, entry.contents, absPath, nil
}

// Import imports file from the filesystem.
func (importer *FileImporter) Import(importedFrom, importedPath string) (contents Contents, foundAt string, err error) {
	// TODO(sbarzowski) Make sure that dir is absolute and resolving of ""
	// is independent from current CWD. The default path should be saved
	// in the importer.
	// We need to relativize the paths in the error formatter, so that the stack traces
	// don't have ugly absolute paths (less readable and messy with golden tests).
	dir, _ := path.Split(importedFrom)
	found, content, foundHere, err := importer.tryPath(dir, importedPath)
	if err != nil {
		return Contents{}, "", err
	}

	for i := len(importer.JPaths) - 1; !found && i >= 0; i-- {
		found, content, foundHere, err = importer.tryPath(importer.JPaths[i], importedPath)
		if err != nil {
			return Contents{}, "", err
		}
	}

	if !found {
		return Contents{}, "", fmt.Errorf("couldn't open import %#v: no match locally or in the Jsonnet library paths", importedPath)
	}
	return content, foundHere, nil
}

// MemoryImporter "imports" data from an in-memory map.
type MemoryImporter struct {
	Data map[string]Contents
}

// Import fetches data from a map entry.
// All paths are treated as absolute keys.
func (importer *MemoryImporter) Import(importedFrom, importedPath string) (contents Contents, foundAt string, err error) {
	if content, ok := importer.Data[importedPath]; ok {
		return content, importedPath, nil
	}
	return Contents{}, "", fmt.Errorf("import not available %v", importedPath)
}
<commit_msg>fix FileImporter not work on windows<commit_after>/*
Copyright 2017 Google Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package jsonnet

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"unsafe"

	"github.com/google/go-jsonnet/ast"
	"github.com/google/go-jsonnet/internal/program"
)

// An Importer imports data from a path.
// TODO(sbarzowski) caching of errors (may require breaking changes)
type Importer interface {
	// Import fetches data from a given path. It may be relative
	// to the file where we do the import. What "relative path"
	// means depends on the importer.
	//
	// It is required that:
	// a) for given (importedFrom, importedPath) the same
	//    (contents, foundAt) are returned on subsequent calls.
	// b) for given foundAt, the contents are always the same
	//
	// It is recommended that if there are multiple locations that
	// need to be probed (e.g. relative + multiple library paths)
	// then all results of all attempts will be cached separately,
	// both nonexistence and contents of existing ones.
	// FileImporter may serve as an example.
	//
	// IMPORTANT: The passed importedFrom might be "" (an empty string).
	// It means that the import is coming from an ad-hoc snippet, e.g.
	// code passed on the command line, read from stdin or passed as
	// a snippet to execute. Importer may have a "default" path to use
	// in such case or it may only allow absolute imports from such
	// "anonymous locations".
	//
	// Importing the same file multiple times must be a cheap operation
	// and shouldn't involve copying the whole file - the same buffer
	// should be returned.
	Import(importedFrom, importedPath string) (contents Contents, foundAt string, err error)
}

// Contents is a representation of imported data. It is a simple
// byte wrapper, which makes it easier to enforce the caching policy.
type Contents struct {
	data *[]byte
}

func (c Contents) String() string {
	// Construct string without copying underlying bytes.
	// NB: This only works because c.data is not modified.
	return *(*string)(unsafe.Pointer(c.data))
}

// Data returns content bytes
func (c Contents) Data() []byte {
	return *c.data
}

// MakeContents creates Contents from a string.
func MakeContents(s string) Contents {
	data := []byte(s)
	return Contents{
		data: &data,
	}
}

// MakeContentsRaw creates Contents from (possibly non-utf8) []byte data.
func MakeContentsRaw(bytes []byte) Contents {
	return Contents{
		data: &bytes,
	}
}

// importCache represents a cache of imported data.
//
// While the user-defined Importer implementations
// are required to cache file content, this cache
// is an additional layer of optimization that caches values
// (i.e. the result of executing the file content).
// It also verifies that the content pointer is the same for two foundAt values.
type importCache struct {
	foundAtVerification map[string]Contents
	astCache            map[string]ast.Node
	codeCache           map[string]potentialValue
	importer            Importer
}

// makeImportCache creates an importCache using an Importer.
func makeImportCache(importer Importer) *importCache {
	return &importCache{
		importer:            importer,
		foundAtVerification: make(map[string]Contents),
		astCache:            make(map[string]ast.Node),
		codeCache:           make(map[string]potentialValue),
	}
}

func (cache *importCache) flushValueCache() {
	cache.codeCache = make(map[string]potentialValue)
}

func (cache *importCache) importData(importedFrom, importedPath string) (contents Contents, foundAt string, err error) {
	contents, foundAt, err = cache.importer.Import(importedFrom, importedPath)
	if err != nil {
		return Contents{}, "", err
	}
	if cached, importedBefore := cache.foundAtVerification[foundAt]; importedBefore {
		if cached != contents {
			panic(fmt.Sprintf("importer problem: a different instance of Contents returned when importing %#v again", foundAt))
		}
	} else {
		cache.foundAtVerification[foundAt] = contents
	}
	return
}

func (cache *importCache) importAST(importedFrom, importedPath string) (ast.Node, string, error) {
	contents, foundAt, err := cache.importData(importedFrom, importedPath)
	if err != nil {
		return nil, "", err
	}
	if cachedNode, isCached := cache.astCache[foundAt]; isCached {
		return cachedNode, foundAt, nil
	}
	node, err := program.SnippetToAST(ast.DiagnosticFileName(foundAt), foundAt, contents.String())
	cache.astCache[foundAt] = node
	return node, foundAt, err
}

// ImportString imports a string, caches it and then returns it.
func (cache *importCache) importString(importedFrom, importedPath string, i *interpreter) (valueString, error) {
	data, _, err := cache.importData(importedFrom, importedPath)
	if err != nil {
		return nil, i.Error(err.Error())
	}
	return makeValueString(data.String()), nil
}

// ImportString imports an array of bytes, caches it and then returns it.
func (cache *importCache) importBinary(importedFrom, importedPath string, i *interpreter) (*valueArray, error) {
	data, _, err := cache.importData(importedFrom, importedPath)
	if err != nil {
		return nil, i.Error(err.Error())
	}
	bytes := data.Data()
	elements := make([]*cachedThunk, len(bytes))
	for i := range bytes {
		elements[i] = readyThunk(intToValue(int(bytes[i])))
	}
	return makeValueArray(elements), nil
}

func nodeToPV(i *interpreter, filename string, node ast.Node) *cachedThunk {
	env := makeInitialEnv(filename, i.baseStd)
	return &cachedThunk{
		env:     &env,
		body:    node,
		content: nil,
	}
}

func codeToPV(i *interpreter, filename string, code string) *cachedThunk {
	node, err := program.SnippetToAST(ast.DiagnosticFileName(filename), "", code)
	if err != nil {
		// TODO(sbarzowski) we should wrap (static) error here
		// within a RuntimeError. Because whether we get this error or not
		// actually depends on what happens in Runtime (whether import gets
		// evaluated).
		// The same thinking applies to external variables.
		return &cachedThunk{err: err}
	}
	return nodeToPV(i, filename, node)
}

// ImportCode imports code from a path.
func (cache *importCache) importCode(importedFrom, importedPath string, i *interpreter) (value, error) {
	node, foundAt, err := cache.importAST(importedFrom, importedPath)
	if err != nil {
		return nil, i.Error(err.Error())
	}
	var pv potentialValue
	if cachedPV, isCached := cache.codeCache[foundAt]; !isCached {
		// File hasn't been parsed and analyzed before, update the cache record.
		env := makeInitialEnv(foundAt, i.baseStd)
		pv = &cachedThunk{
			env:     &env,
			body:    node,
			content: nil,
		}
		cache.codeCache[foundAt] = pv
	} else {
		pv = cachedPV
	}
	return i.evaluatePV(pv)
}

// Concrete importers
// -------------------------------------

// FileImporter imports data from the filesystem.
type FileImporter struct {
	fsCache map[string]*fsCacheEntry
	JPaths  []string
}

type fsCacheEntry struct {
	contents Contents
	exists   bool
}

func (importer *FileImporter) tryPath(dir, importedPath string) (found bool, contents Contents, foundHere string, err error) {
	if importer.fsCache == nil {
		importer.fsCache = make(map[string]*fsCacheEntry)
	}
	var absPath string
	if filepath.IsAbs(importedPath) {
		absPath = importedPath
	} else {
		absPath = filepath.Join(dir, importedPath)
	}
	var entry *fsCacheEntry
	if cacheEntry, isCached := importer.fsCache[absPath]; isCached {
		entry = cacheEntry
	} else {
		contentBytes, err := ioutil.ReadFile(absPath)
		if err != nil {
			if os.IsNotExist(err) {
				entry = &fsCacheEntry{
					exists: false,
				}
			} else {
				return false, Contents{}, "", err
			}
		} else {
			entry = &fsCacheEntry{
				exists:   true,
				contents: MakeContentsRaw(contentBytes),
			}
		}
		importer.fsCache[absPath] = entry
	}
	return entry.exists, entry.contents, absPath, nil
}

// Import imports file from the filesystem.
func (importer *FileImporter) Import(importedFrom, importedPath string) (contents Contents, foundAt string, err error) {
	// TODO(sbarzowski) Make sure that dir is absolute and resolving of ""
	// is independent from current CWD. The default path should be saved
	// in the importer.
	// We need to relativize the paths in the error formatter, so that the stack traces
	// don't have ugly absolute paths (less readable and messy with golden tests).
	dir, _ := filepath.Split(importedFrom)
	found, content, foundHere, err := importer.tryPath(dir, importedPath)
	if err != nil {
		return Contents{}, "", err
	}

	for i := len(importer.JPaths) - 1; !found && i >= 0; i-- {
		found, content, foundHere, err = importer.tryPath(importer.JPaths[i], importedPath)
		if err != nil {
			return Contents{}, "", err
		}
	}

	if !found {
		return Contents{}, "", fmt.Errorf("couldn't open import %#v: no match locally or in the Jsonnet library paths", importedPath)
	}
	return content, foundHere, nil
}

// MemoryImporter "imports" data from an in-memory map.
type MemoryImporter struct {
	Data map[string]Contents
}

// Import fetches data from a map entry.
// All paths are treated as absolute keys.
func (importer *MemoryImporter) Import(importedFrom, importedPath string) (contents Contents, foundAt string, err error) {
	if content, ok := importer.Data[importedPath]; ok {
		return content, importedPath, nil
	}
	return Contents{}, "", fmt.Errorf("import not available %v", importedPath)
}
<|endoftext|>


<commit_before>package ionic

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/url"

	"github.com/ion-channel/ionic/scanner"
)

const (
	scannerAnalyzeProjectEndpoint     = "v1/scanner/analyzeProject"
	scannerGetAnalysisStatusEndpoint = "v1/scanner/getAnalysisStatus"
	scannerAddScanEndpoint = "v1/scanner/addScanResult"
)

type analyzeRequest struct {
	TeamID    string `json:"team_id"`
	ProjectID string `json:"project_id"`
}

type addScanRequest struct {
	TeamID    string               `json:"team_id"`
	ProjectID string               `json:"project_id"`
	ID        string               `json:"analysis_id"`
	Status    string               `json:"status"`
	Results   scanner.ExternalScan `json:"result"`
	Type      string               `json:"scan-type"`
}

func (ic *IonClient) AnalyzeProject(teamID, projectID string) (*scanner.AnalysisStatus, error) {
	request := &analyzeRequest{}
	request.TeamID = teamID
	request.ProjectID = projectID

	b, err := json.Marshal(request)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal request body to JSON: %v", err.Error())
	}

	buff := bytes.NewBuffer(b)
	b, err = ic.post(scannerAnalyzeProjectEndpoint, nil, *buff, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to start analysis: %v", err.Error())
	}

	var a scanner.AnalysisStatus
	err = json.Unmarshal(b, &a)
	if err != nil {
		return nil, fmt.Errorf("failed to get analysis status: %v", err.Error())
	}

	return &a, nil
}

func (ic *IonClient) GetAnalysisStatus(id, teamID, projectID string) (*scanner.AnalysisStatus, error) {
	params := &url.Values{}
	params.Set("id", id)
	params.Set("team_id", teamID)
	params.Set("project_id", projectID)

	b, err := ic.get(scannerGetAnalysisStatusEndpoint, params, nil, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to get analysis: %v", err.Error())
	}

	var a scanner.AnalysisStatus
	err = json.Unmarshal(b, &a)
	if err != nil {
		return nil, fmt.Errorf("failed to get analysis: %v", err.Error())
	}

	return &a, nil
}

func (ic *IonClient) AddScanResult(id, teamID, projectID, status, scanType string, scanResults scanner.ExternalScan) (*scanner.AnalysisStatus, error) {
	request := &addScanRequest{}
	request.ID = id
	request.TeamID = teamID
	request.ProjectID = projectID
	request.Results = scanResults
	request.Type = scanType

	b, err := json.Marshal(request)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal request body to JSON: %v", err.Error())
	}

	buff := bytes.NewBuffer(b)
	b, err = ic.post(scannerAddScanEndpoint, nil, *buff, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to start analysis: %v", err.Error())
	}

	var a scanner.AnalysisStatus
	err = json.Unmarshal(b, &a)
	if err != nil {
		return nil, fmt.Errorf("failed to get analysis status: %v", err.Error())
	}

	return &a, nil
}
<commit_msg>correct the names of the add result params<commit_after>package ionic

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/url"

	"github.com/ion-channel/ionic/scanner"
)

const (
	scannerAnalyzeProjectEndpoint     = "v1/scanner/analyzeProject"
	scannerGetAnalysisStatusEndpoint = "v1/scanner/getAnalysisStatus"
	scannerAddScanEndpoint = "v1/scanner/addScanResult"
)

type analyzeRequest struct {
	TeamID    string `json:"team_id"`
	ProjectID string `json:"project_id"`
}

type addScanRequest struct {
	TeamID    string               `json:"team_id"`
	ProjectID string               `json:"project_id"`
	ID        string               `json:"analysis_id"`
	Status    string               `json:"status"`
	Results   scanner.ExternalScan `json:"results"`
	Type      string               `json:"scan_type"`
}

func (ic *IonClient) AnalyzeProject(teamID, projectID string) (*scanner.AnalysisStatus, error) {
	request := &analyzeRequest{}
	request.TeamID = teamID
	request.ProjectID = projectID

	b, err := json.Marshal(request)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal request body to JSON: %v", err.Error())
	}

	buff := bytes.NewBuffer(b)
	b, err = ic.post(scannerAnalyzeProjectEndpoint, nil, *buff, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to start analysis: %v", err.Error())
	}

	var a scanner.AnalysisStatus
	err = json.Unmarshal(b, &a)
	if err != nil {
		return nil, fmt.Errorf("failed to get analysis status: %v", err.Error())
	}

	return &a, nil
}

func (ic *IonClient) GetAnalysisStatus(id, teamID, projectID string) (*scanner.AnalysisStatus, error) {
	params := &url.Values{}
	params.Set("id", id)
	params.Set("team_id", teamID)
	params.Set("project_id", projectID)

	b, err := ic.get(scannerGetAnalysisStatusEndpoint, params, nil, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to get analysis: %v", err.Error())
	}

	var a scanner.AnalysisStatus
	err = json.Unmarshal(b, &a)
	if err != nil {
		return nil, fmt.Errorf("failed to get analysis: %v", err.Error())
	}

	return &a, nil
}

func (ic *IonClient) AddScanResult(id, teamID, projectID, status, scanType string, scanResults scanner.ExternalScan) (*scanner.AnalysisStatus, error) {
	request := &addScanRequest{}
	request.ID = id
	request.TeamID = teamID
	request.ProjectID = projectID
	request.Results = scanResults
	request.Type = scanType

	b, err := json.Marshal(request)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal request body to JSON: %v", err.Error())
	}

	buff := bytes.NewBuffer(b)
	b, err = ic.post(scannerAddScanEndpoint, nil, *buff, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to start analysis: %v", err.Error())
	}

	var a scanner.AnalysisStatus
	err = json.Unmarshal(b, &a)
	if err != nil {
		return nil, fmt.Errorf("failed to get analysis status: %v", err.Error())
	}

	return &a, nil
}
<|endoftext|>


<commit_before>package jo

import (
	"fmt"
)

// Valid scanner states.
const (
	sClean = iota
	sEOF

	sObjectKeyOrBrace
	sObjectColon
	sObjectCommaOrBrace
	sObjectKey

	sArrayElementOrBracket
	sArrayCommaOrBracket

	sString
	sStringEsc
	sStringUnicode
	sStringUnicode1
	sStringUnicode12
	sStringUnicode123

	sNumberNeg
	sNumberZero
	sNumberDigit
	sNumberDot
	sNumberDotDigit
	sNumberExp
	sNumberExpSign
	sNumberExpDigit

	sBoolT
	sBoolTr
	sBoolTru

	sBoolF
	sBoolFa
	sBoolFal
	sBoolFals

	sNullN
	sNullNu
	sNullNul
)

// Scanner is a JSON scanning state machine. The zero value for Scanner is
// ready to be used without any further initialization.
type Scanner struct {
	state int
	err   error
	stack []int
	size  int
	isKey bool
}

// Scan feeds another byte to the scanner.
//
// The first return value, refered to as an opcode, tells the caller about
// significant parsing events like beginning and ending values, so that the
// caller can follow along if it wishes.
//
// The second return value is used to indicate whether or not, which is
// necessary because of number literals (is 123 a whole value, or just the
// beginning of 12345?). Even though it will only ever be either 1 or 0, it is
// an integer rather than a boolean to allow for these kinds of constructs:
//
//     for i := 0; i < len(input); {
//         _, n := s.Scan(input[i])
//         i += n
//     }
func (s *Scanner) Scan(c byte) (Op, int) {
rewind:
	switch s.state {
	case sClean:
		switch c {
		case ' ', '\t', '\n', '\r':
			return OpSpace, 1
		case '{':
			s.state = sObjectKeyOrBrace
			return OpObjectStart, 1
		case '[':
			s.state = sArrayElementOrBracket
			return OpArrayStart, 1
		case '"':
			s.state = sString
			s.isKey = false
			return OpStringStart, 1
		case '-':
			s.state = sNumberNeg
			return OpNumberStart, 1
		case '0':
			s.state = sNumberZero
			return OpNumberStart, 1
		case '1', '2', '3', '4', '5', '6', '7', '8', '9':
			s.state = sNumberDigit
			return OpNumberStart, 1
		case 't':
			s.state = sBoolT
			return OpBoolStart, 1
		case 'f':
			s.state = sBoolF
			return OpBoolStart, 1
		case 'n':
			s.state = sNullN
			return OpNullStart, 1
		}

	case sObjectKeyOrBrace:
		switch c {
		case ' ', '\t', '\r', '\n':
			return OpSpace, 1
		case '"':
			s.state = sString
			s.isKey = true
			s.push(sObjectColon)
			return OpObjectKeyStart, 1
		case '}':
			s.state = s.pop()
			return OpObjectEnd, 1
		}
		return s.errorf(`expected object key or '}', found %q`, c)

	case sObjectColon:
		switch c {
		case ' ', '\t', 'r', '\n':
			return OpSpace, 1
		case ':':
			s.state = sClean
			s.push(sObjectCommaOrBrace)
			return OpContinue, 1
		}
		return s.errorf(`expected ':' after object key, found %q`, c)

	case sObjectCommaOrBrace:
		switch c {
		case ' ', '\t', '\r', '\n':
			return OpSpace, 1
		case ',':
			s.state = sObjectKey
			return OpContinue, 1
		case '}':
			s.state = s.pop()
			return OpObjectEnd, 1
		}
		return s.errorf(`expected object key or '}' after object value, found %q`, c)

	case sObjectKey:
		switch c {
		case ' ', '\t', '\r', '\n':
			return OpSpace, 1
		case '"':
			s.state = sString
			s.isKey = true
			s.push(sObjectColon)
			return OpObjectKeyStart, 1
		}
		return s.errorf(`expected object key after ',', found %q`, c)

	case sArrayElementOrBracket:
		switch c {
		case ' ', '\t', '\r', '\n':
			return OpSpace, 1
		case ']':
			s.state = s.pop()
			return OpArrayEnd, 1
		}
		s.push(sArrayCommaOrBracket)
		s.state = sClean
		goto rewind

	case sArrayCommaOrBracket:
		switch c {
		case ' ', '\t', '\n', '\r':
			return OpSpace, 1
		case ',':
			s.state = sArrayElementOrBracket
			return OpContinue, 1
		case ']':
			s.state = s.pop()
			return OpArrayEnd, 1
		}
		return s.errorf(`expected ',' or ']' after array element, found %q`, c)

	case sString:
		if c == '"' {
			s.state = s.pop()
			if s.isKey {
				return OpObjectKeyEnd, 1
			}
			return OpStringEnd, 1
		}
		if c == '\\' {
			s.state = sStringEsc
			return OpContinue, 1
		}
		if c >= 0x20 {
			return OpContinue, 1
		}
		return s.errorf(`unexpected control character in string literal`)

	case sStringEsc:
		switch c {
		case 'b', 'f', 'n', 'r', 't', '\\', '/', '"':
			s.state = sString
			return OpContinue, 1
		case 'u':
			s.state = sStringUnicode
			return OpContinue, 1
		}
		return s.errorf(`illegal escape sequence in string literal`)

	case sStringUnicode:
		if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
			s.state = sStringUnicode1
			return OpContinue, 1
		}
		return s.errorf(`illegal unicode escape sequence in string literal`)

	case sStringUnicode1:
		if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
			s.state = sStringUnicode12
			return OpContinue, 1
		}
		return s.errorf(`illegal unicode escape sequence in string literal`)

	case sStringUnicode12:
		if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
			s.state = sStringUnicode123
			return OpContinue, 1
		}
		return s.errorf(`illegal unicode escape sequence in string literal`)

	case sStringUnicode123:
		if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
			s.state = sString
			return OpContinue, 1
		}
		return s.errorf(`illegal unicode escape sequence in string literal`)

	case sNumberNeg:
		if c == '0' {
			s.state = sNumberZero
			return OpContinue, 1
		}
		if '1' <= c && c <= '9' {
			s.state = sNumberDigit
			return OpContinue, 1
		}
		return s.errorf(`expected digit after "-", found %q`, c)

	case sNumberDigit:
		if '0' <= c && c <= '9' {
			return OpContinue, 1
		}
		fallthrough

	case sNumberZero:
		if c == '.' {
			s.state = sNumberDot
			return OpContinue, 1
		}
		if c == 'e' || c == 'E' {
			s.state = sNumberExp
			return OpContinue, 1
		}
		s.state = s.pop()
		return OpNumberEnd, 0

	case sNumberDot:
		if '0' <= c && c <= '9' {
			s.state = sNumberDotDigit
			return OpContinue, 1
		}
		return s.errorf(`expected digit after decimal point, found %q`, c)

	case sNumberDotDigit:
		if '0' <= c && c <= '9' {
			return OpContinue, 1
		}
		if c == 'e' || c == 'E' {
			s.state = sNumberExp
			return OpContinue, 1
		}
		s.state = s.pop()
		return OpNumberEnd, 0

	case sNumberExp:
		if '0' <= c && c <= '9' {
			s.state = sNumberExpDigit
			return OpContinue, 1
		}
		if c == '-' || c == '+' {
			s.state = sNumberExpSign
			return OpContinue, 1
		}
		return s.errorf(`expected sign or digit in exponent, found %q`, c)

	case sNumberExpSign:
		if '0' <= c && c <= '9' {
			s.state = sNumberExpDigit
			return OpContinue, 1
		}
		return s.errorf(`expected digit after exponent sign, found %q`)

	case sNumberExpDigit:
		if '0' <= c && c <= '9' {
			return OpContinue, 1
		}
		s.state = s.pop()
		return OpNumberEnd, 0

	case sBoolT:
		if c == 'r' {
			s.state = sBoolTr
			return OpContinue, 1
		}
		return s.errorf(`expected 'r' after "t", found %q`, c)

	case sBoolTr:
		if c == 'u' {
			s.state = sBoolTru
			return OpContinue, 1
		}
		return s.errorf(`expected 'u' after "tr", found %q`, c)

	case sBoolTru:
		if c == 'e' {
			s.state = s.pop()
			return OpBoolEnd, 1
		}
		return s.errorf(`expected 'e' after "tru", found %q`, c)

	case sBoolF:
		if c == 'a' {
			s.state = sBoolFa
			return OpContinue, 1
		}
		return s.errorf(`expected 'a' after "f", found %q`, c)

	case sBoolFa:
		if c == 'l' {
			s.state = sBoolFal
			return OpContinue, 1
		}
		return s.errorf(`expected 'l' after "fa", found %q`, c)

	case sBoolFal:
		if c == 's' {
			s.state = sBoolFals
			return OpContinue, 1
		}
		return s.errorf(`expected 's' after "fal", found %q`, c)

	case sBoolFals:
		if c == 'e' {
			s.state = s.pop()
			return OpBoolEnd, 1
		}
		return s.errorf(`expected 'e' after "fals", found %q`, c)

	case sNullN:
		if c == 'u' {
			s.state = sNullNu
			return OpContinue, 1
		}
		return s.errorf(`expected 'u' after "n", found %q`, c)

	case sNullNu:
		if c == 'l' {
			s.state = sNullNul
			return OpContinue, 1
		}
		return s.errorf(`expected 'l' after "nu", found %q`, c)

	case sNullNul:
		if c == 'l' {
			s.state = s.pop()
			return OpNullEnd, 1
		}
		return s.errorf(`expected 'l' after "nul", found %q`, c)

	case sEOF:
		if c <= ' ' && (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
			return OpSpace, 1
		}
		return s.errorf(`unexpected %q after top-level value`, c)
	}

	return OpContinue, 1
}

// Eof signals the scanner that the end of input has been reached. It returns
// an opcode, just as s.Scan does, which will be either OpEOF, OpNumberEnd or
// OpSyntaxError.
func (s *Scanner) Eof() Op {
	switch s.state {
	case sNumberZero, sNumberDigit, sNumberDotDigit, sNumberExpDigit:
		if len(s.stack) == 0 {
			s.state = sEOF
			return OpNumberEnd
		}
	case sEOF:
		return OpEOF
	}

	op, _ := s.errorf(`unexpected end of JSON input`)
	return op
}

// LastError returns the last error raised by the Scan or Eof methods.
func (s *Scanner) LastError() error {
	return s.err
}

// Reset resets the scanner's internal state.
func (s *Scanner) Reset() {
	s.state = 0
	s.err = nil
	s.stack = s.stack[:0]
	s.size = 0
}

// push adds a new state to the stack.
func (s *Scanner) push(x int) {
	if len(s.stack) == s.size {
		s.stack = append(s.stack, x)
	} else {
		s.stack[s.size] = x
	}
	s.size++
}

// pop takes the top state from the stack.
func (s *Scanner) pop() int {
	if s.size == 0 {
		return sEOF
	}

	s.size--
	return s.stack[s.size]
}

// errorf is a convenience function which both sets the scanner's error
// field and returns an OpSyntaxError opcode.
func (s *Scanner) errorf(format string, args ...interface{}) (Op, int) {
	s.err = fmt.Errorf(format, args...)
	return OpSyntaxError, 0
}
<commit_msg>Actually detect top-level syntax errors<commit_after>package jo

import (
	"fmt"
)

// Valid scanner states.
const (
	sClean = iota
	sEOF

	sObjectKeyOrBrace
	sObjectColon
	sObjectCommaOrBrace
	sObjectKey

	sArrayElementOrBracket
	sArrayCommaOrBracket

	sString
	sStringEsc
	sStringUnicode
	sStringUnicode1
	sStringUnicode12
	sStringUnicode123

	sNumberNeg
	sNumberZero
	sNumberDigit
	sNumberDot
	sNumberDotDigit
	sNumberExp
	sNumberExpSign
	sNumberExpDigit

	sBoolT
	sBoolTr
	sBoolTru

	sBoolF
	sBoolFa
	sBoolFal
	sBoolFals

	sNullN
	sNullNu
	sNullNul
)

// Scanner is a JSON scanning state machine. The zero value for Scanner is
// ready to be used without any further initialization.
type Scanner struct {
	state int
	err   error
	stack []int
	size  int
	isKey bool
}

// Scan feeds another byte to the scanner.
//
// The first return value, refered to as an opcode, tells the caller about
// significant parsing events like beginning and ending values, so that the
// caller can follow along if it wishes.
//
// The second return value is used to indicate whether or not, which is
// necessary because of number literals (is 123 a whole value, or just the
// beginning of 12345?). Even though it will only ever be either 1 or 0, it is
// an integer rather than a boolean to allow for these kinds of constructs:
//
//     for i := 0; i < len(input); {
//         _, n := s.Scan(input[i])
//         i += n
//     }
func (s *Scanner) Scan(c byte) (Op, int) {
rewind:
	switch s.state {
	case sClean:
		switch c {
		case ' ', '\t', '\n', '\r':
			return OpSpace, 1
		case '{':
			s.state = sObjectKeyOrBrace
			return OpObjectStart, 1
		case '[':
			s.state = sArrayElementOrBracket
			return OpArrayStart, 1
		case '"':
			s.state = sString
			s.isKey = false
			return OpStringStart, 1
		case '-':
			s.state = sNumberNeg
			return OpNumberStart, 1
		case '0':
			s.state = sNumberZero
			return OpNumberStart, 1
		case '1', '2', '3', '4', '5', '6', '7', '8', '9':
			s.state = sNumberDigit
			return OpNumberStart, 1
		case 't':
			s.state = sBoolT
			return OpBoolStart, 1
		case 'f':
			s.state = sBoolF
			return OpBoolStart, 1
		case 'n':
			s.state = sNullN
			return OpNullStart, 1
		}
		return s.errorf(`expected start of JSON value, found %q`, c)

	case sObjectKeyOrBrace:
		switch c {
		case ' ', '\t', '\r', '\n':
			return OpSpace, 1
		case '"':
			s.state = sString
			s.isKey = true
			s.push(sObjectColon)
			return OpObjectKeyStart, 1
		case '}':
			s.state = s.pop()
			return OpObjectEnd, 1
		}
		return s.errorf(`expected object key or '}', found %q`, c)

	case sObjectColon:
		switch c {
		case ' ', '\t', 'r', '\n':
			return OpSpace, 1
		case ':':
			s.state = sClean
			s.push(sObjectCommaOrBrace)
			return OpContinue, 1
		}
		return s.errorf(`expected ':' after object key, found %q`, c)

	case sObjectCommaOrBrace:
		switch c {
		case ' ', '\t', '\r', '\n':
			return OpSpace, 1
		case ',':
			s.state = sObjectKey
			return OpContinue, 1
		case '}':
			s.state = s.pop()
			return OpObjectEnd, 1
		}
		return s.errorf(`expected object key or '}' after object value, found %q`, c)

	case sObjectKey:
		switch c {
		case ' ', '\t', '\r', '\n':
			return OpSpace, 1
		case '"':
			s.state = sString
			s.isKey = true
			s.push(sObjectColon)
			return OpObjectKeyStart, 1
		}
		return s.errorf(`expected object key after ',', found %q`, c)

	case sArrayElementOrBracket:
		switch c {
		case ' ', '\t', '\r', '\n':
			return OpSpace, 1
		case ']':
			s.state = s.pop()
			return OpArrayEnd, 1
		}
		s.push(sArrayCommaOrBracket)
		s.state = sClean
		goto rewind

	case sArrayCommaOrBracket:
		switch c {
		case ' ', '\t', '\n', '\r':
			return OpSpace, 1
		case ',':
			s.state = sArrayElementOrBracket
			return OpContinue, 1
		case ']':
			s.state = s.pop()
			return OpArrayEnd, 1
		}
		return s.errorf(`expected ',' or ']' after array element, found %q`, c)

	case sString:
		if c == '"' {
			s.state = s.pop()
			if s.isKey {
				return OpObjectKeyEnd, 1
			}
			return OpStringEnd, 1
		}
		if c == '\\' {
			s.state = sStringEsc
			return OpContinue, 1
		}
		if c >= 0x20 {
			return OpContinue, 1
		}
		return s.errorf(`unexpected control character in string literal`)

	case sStringEsc:
		switch c {
		case 'b', 'f', 'n', 'r', 't', '\\', '/', '"':
			s.state = sString
			return OpContinue, 1
		case 'u':
			s.state = sStringUnicode
			return OpContinue, 1
		}
		return s.errorf(`illegal escape sequence in string literal`)

	case sStringUnicode:
		if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
			s.state = sStringUnicode1
			return OpContinue, 1
		}
		return s.errorf(`illegal unicode escape sequence in string literal`)

	case sStringUnicode1:
		if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
			s.state = sStringUnicode12
			return OpContinue, 1
		}
		return s.errorf(`illegal unicode escape sequence in string literal`)

	case sStringUnicode12:
		if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
			s.state = sStringUnicode123
			return OpContinue, 1
		}
		return s.errorf(`illegal unicode escape sequence in string literal`)

	case sStringUnicode123:
		if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
			s.state = sString
			return OpContinue, 1
		}
		return s.errorf(`illegal unicode escape sequence in string literal`)

	case sNumberNeg:
		if c == '0' {
			s.state = sNumberZero
			return OpContinue, 1
		}
		if '1' <= c && c <= '9' {
			s.state = sNumberDigit
			return OpContinue, 1
		}
		return s.errorf(`expected digit after "-", found %q`, c)

	case sNumberDigit:
		if '0' <= c && c <= '9' {
			return OpContinue, 1
		}
		fallthrough

	case sNumberZero:
		if c == '.' {
			s.state = sNumberDot
			return OpContinue, 1
		}
		if c == 'e' || c == 'E' {
			s.state = sNumberExp
			return OpContinue, 1
		}
		s.state = s.pop()
		return OpNumberEnd, 0

	case sNumberDot:
		if '0' <= c && c <= '9' {
			s.state = sNumberDotDigit
			return OpContinue, 1
		}
		return s.errorf(`expected digit after decimal point, found %q`, c)

	case sNumberDotDigit:
		if '0' <= c && c <= '9' {
			return OpContinue, 1
		}
		if c == 'e' || c == 'E' {
			s.state = sNumberExp
			return OpContinue, 1
		}
		s.state = s.pop()
		return OpNumberEnd, 0

	case sNumberExp:
		if '0' <= c && c <= '9' {
			s.state = sNumberExpDigit
			return OpContinue, 1
		}
		if c == '-' || c == '+' {
			s.state = sNumberExpSign
			return OpContinue, 1
		}
		return s.errorf(`expected sign or digit in exponent, found %q`, c)

	case sNumberExpSign:
		if '0' <= c && c <= '9' {
			s.state = sNumberExpDigit
			return OpContinue, 1
		}
		return s.errorf(`expected digit after exponent sign, found %q`)

	case sNumberExpDigit:
		if '0' <= c && c <= '9' {
			return OpContinue, 1
		}
		s.state = s.pop()
		return OpNumberEnd, 0

	case sBoolT:
		if c == 'r' {
			s.state = sBoolTr
			return OpContinue, 1
		}
		return s.errorf(`expected 'r' after "t", found %q`, c)

	case sBoolTr:
		if c == 'u' {
			s.state = sBoolTru
			return OpContinue, 1
		}
		return s.errorf(`expected 'u' after "tr", found %q`, c)

	case sBoolTru:
		if c == 'e' {
			s.state = s.pop()
			return OpBoolEnd, 1
		}
		return s.errorf(`expected 'e' after "tru", found %q`, c)

	case sBoolF:
		if c == 'a' {
			s.state = sBoolFa
			return OpContinue, 1
		}
		return s.errorf(`expected 'a' after "f", found %q`, c)

	case sBoolFa:
		if c == 'l' {
			s.state = sBoolFal
			return OpContinue, 1
		}
		return s.errorf(`expected 'l' after "fa", found %q`, c)

	case sBoolFal:
		if c == 's' {
			s.state = sBoolFals
			return OpContinue, 1
		}
		return s.errorf(`expected 's' after "fal", found %q`, c)

	case sBoolFals:
		if c == 'e' {
			s.state = s.pop()
			return OpBoolEnd, 1
		}
		return s.errorf(`expected 'e' after "fals", found %q`, c)

	case sNullN:
		if c == 'u' {
			s.state = sNullNu
			return OpContinue, 1
		}
		return s.errorf(`expected 'u' after "n", found %q`, c)

	case sNullNu:
		if c == 'l' {
			s.state = sNullNul
			return OpContinue, 1
		}
		return s.errorf(`expected 'l' after "nu", found %q`, c)

	case sNullNul:
		if c == 'l' {
			s.state = s.pop()
			return OpNullEnd, 1
		}
		return s.errorf(`expected 'l' after "nul", found %q`, c)

	case sEOF:
		if c <= ' ' && (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
			return OpSpace, 1
		}
		return s.errorf(`unexpected %q after top-level value`, c)
	}

	return OpContinue, 1
}

// Eof signals the scanner that the end of input has been reached. It returns
// an opcode, just as s.Scan does, which will be either OpEOF, OpNumberEnd or
// OpSyntaxError.
func (s *Scanner) Eof() Op {
	switch s.state {
	case sNumberZero, sNumberDigit, sNumberDotDigit, sNumberExpDigit:
		if len(s.stack) == 0 {
			s.state = sEOF
			return OpNumberEnd
		}
	case sEOF:
		return OpEOF
	}

	op, _ := s.errorf(`unexpected end of JSON input`)
	return op
}

// LastError returns the last error raised by the Scan or Eof methods.
func (s *Scanner) LastError() error {
	return s.err
}

// Reset resets the scanner's internal state.
func (s *Scanner) Reset() {
	s.state = 0
	s.err = nil
	s.stack = s.stack[:0]
	s.size = 0
}

// push adds a new state to the stack.
func (s *Scanner) push(x int) {
	if len(s.stack) == s.size {
		s.stack = append(s.stack, x)
	} else {
		s.stack[s.size] = x
	}
	s.size++
}

// pop takes the top state from the stack.
func (s *Scanner) pop() int {
	if s.size == 0 {
		return sEOF
	}

	s.size--
	return s.stack[s.size]
}

// errorf is a convenience function which both sets the scanner's error
// field and returns an OpSyntaxError opcode.
func (s *Scanner) errorf(format string, args ...interface{}) (Op, int) {
	s.err = fmt.Errorf(format, args...)
	return OpSyntaxError, 0
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/sha512"
	"encoding/hex"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
)

func sha512sum(filePath string) (result string, err error) {
	file, err := os.Open(filePath)
	if err != nil {
		return
	}
	defer file.Close()

	hash := sha512.New()
	_, err = io.Copy(hash, file)
	if err != nil {
		return
	}
	result = hex.EncodeToString(hash.Sum(nil))
	return
}

func Worker(in chan File, out chan File) {
	for {
		FileToProcess, ok := <-in
		if ok == false {
							fmt.Println("Shutting down a thread :)")
			return
		}
		hash, err := sha512sum(FileToProcess.Path)
		if err != nil {
			log.Println(err)
			continue
		}
		FileToProcess.Checksum = hash
		out <- FileToProcess
	}
}

func scanfiles(location string, MaxWorkerThreads int, comm chan int) (files []File) {
	WFin := make(chan File)
	WFout := make(chan File)
	for i := MaxWorkerThreads; i > 0; i-- {
		go Worker(WFin, WFout)
	}
	var walkcallback = func(path string, fileinfo os.FileInfo, inputerror error) (err error) {
		var f File
		f.Path = path
		f.Finfo = fileinfo
		WFin <- f
		return
	}
	go func() {
		err := filepath.Walk(location, walkcallback)
		close(WFin)
		if err != nil {
			panic(err)
		}
	}()
	for {
		select {
		case file := <-WFout:
			fmt.Println(file)
			files = append(files, file)
		default:
			break
		}
		select {
		case msg := <-comm:
			if msg == StopCode {
				close(WFin)
				files = nil
				break
			}
		default:
		}
	}
	fmt.Println(files)
	close(WFin)
	return
}
<commit_msg>Modify checksum functions buffer size for peak efficiency<commit_after>package main

import (
	"crypto/sha512"
	"encoding/hex"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
)

func sha512sum(filePath string) (result string, err error) {
	file, err := os.Open(filePath)
	if err != nil {
		return
	}
	defer file.Close()

	buf := make([]byte, 128)

	hash := sha512.New()
	_, err = io.CopyBuffer(hash, file, buf)
	if err != nil {
		return
	}
	result = hex.EncodeToString(hash.Sum(nil))
	return
}

func Worker(in chan File, out chan File) {
	for {
		FileToProcess, ok := <-in
		if ok == false {
							fmt.Println("Shutting down a thread :)")
			return
		}
		hash, err := sha512sum(FileToProcess.Path)
		if err != nil {
			log.Println(err)
			continue
		}
		FileToProcess.Checksum = hash
		out <- FileToProcess
	}
}

func scanfiles(location string, MaxWorkerThreads int, comm chan int) (files []File) {
	WFin := make(chan File)
	WFout := make(chan File)
	for i := MaxWorkerThreads; i > 0; i-- {
		go Worker(WFin, WFout)
	}
	var walkcallback = func(path string, fileinfo os.FileInfo, inputerror error) (err error) {
		var f File
		f.Path = path
		f.Finfo = fileinfo
		WFin <- f
		return
	}
	go func() {
		err := filepath.Walk(location, walkcallback)
		close(WFin)
		if err != nil {
			panic(err)
		}
	}()
	for {
		select {
		case file := <-WFout:
			fmt.Println(file)
			files = append(files, file)
		default:
			break
		}
		select {
		case msg := <-comm:
			if msg == StopCode {
				close(WFin)
				files = nil
				break
			}
		default:
		}
	}
	fmt.Println(files)
	close(WFin)
	return
}
<|endoftext|>


<commit_before>// Package azureBlob implements the fs interfaces
// for the local file system
package azureBlob

import (
	"fmt"
	"io"
	"os"
	"time"

	log "github.com/Sirupsen/logrus"

	"github.com/Azure/azure-sdk-for-go/storage"
	"github.com/mindflavor/ftpserver2/ftp/fs"
)

type azureBlob struct {
	name    string
	path    string
	size    int64
	modTime time.Time
	mode    os.FileMode
	client  storage.BlobStorageClient
}

// New initializes a new fs.File with the
// specified parameters.
func New(name string, path string, size int64, modTime time.Time, mode os.FileMode, client storage.BlobStorageClient) fs.File {
	log.WithFields(log.Fields{"name": name, "path": path, "size": size, "modTime": modTime, "mode": mode}).Debug("azureBlob::New called")

	return &azureBlob{
		name:    name,
		path:    path,
		size:    size,
		modTime: modTime,
		mode:    mode,
		client:  client,
	}
}

func (b *azureBlob) String() string {
	return fmt.Sprintf("{name=%s, path=%s, size=%d, mode=%s, modTime=%s}", b.name, b.path, b.size, b.mode, b.modTime)
}

func (b *azureBlob) Name() string {
	return b.name
}

func (b *azureBlob) Path() string {
	return b.path
}

func (b *azureBlob) FullPath() string {
	return b.path + "/" + b.name
}

func (b *azureBlob) Size() int64 {
	return b.size
}

func (b *azureBlob) IsDirectory() bool {
	return false
}

func (b *azureBlob) ModTime() time.Time {
	return b.modTime
}

func (b *azureBlob) Mode() string {
	return b.mode.String()
}

func (b *azureBlob) Read(startPosition int64) (io.ReadCloser, error) {
	log.WithFields(log.Fields{"b": b, "startPosition": startPosition}).Debug("azureBlob::azureBlob::Read called")
	return b.client.GetBlob(b.path, b.name)
}

func (b *azureBlob) Write() (io.WriteCloser, error) {
	log.WithFields(log.Fields{"b": b}).Debug("azureBlob::azureBlob::Write called")
	return NewBlockBlobWriter(b)
}

func (b *azureBlob) Clone() fs.File {
	return &azureBlob{
		name:    b.name,
		path:    b.path,
		size:    b.size,
		modTime: b.modTime,
		mode:    b.mode,
		client:  b.client,
	}
}

func (b azureBlob) Delete() error {
	return b.client.DeleteBlob(b.path, b.name)
}
<commit_msg>add 3rd argument to DeleteBlob method<commit_after>// Package azureBlob implements the fs interfaces
// for the local file system
package azureBlob

import (
	"fmt"
	"io"
	"os"
	"time"

	log "github.com/Sirupsen/logrus"

	"github.com/Azure/azure-sdk-for-go/storage"
	"github.com/mindflavor/ftpserver2/ftp/fs"
)

type azureBlob struct {
	name    string
	path    string
	size    int64
	modTime time.Time
	mode    os.FileMode
	client  storage.BlobStorageClient
}

// New initializes a new fs.File with the
// specified parameters.
func New(name string, path string, size int64, modTime time.Time, mode os.FileMode, client storage.BlobStorageClient) fs.File {
	log.WithFields(log.Fields{"name": name, "path": path, "size": size, "modTime": modTime, "mode": mode}).Debug("azureBlob::New called")

	return &azureBlob{
		name:    name,
		path:    path,
		size:    size,
		modTime: modTime,
		mode:    mode,
		client:  client,
	}
}

func (b *azureBlob) String() string {
	return fmt.Sprintf("{name=%s, path=%s, size=%d, mode=%s, modTime=%s}", b.name, b.path, b.size, b.mode, b.modTime)
}

func (b *azureBlob) Name() string {
	return b.name
}

func (b *azureBlob) Path() string {
	return b.path
}

func (b *azureBlob) FullPath() string {
	return b.path + "/" + b.name
}

func (b *azureBlob) Size() int64 {
	return b.size
}

func (b *azureBlob) IsDirectory() bool {
	return false
}

func (b *azureBlob) ModTime() time.Time {
	return b.modTime
}

func (b *azureBlob) Mode() string {
	return b.mode.String()
}

func (b *azureBlob) Read(startPosition int64) (io.ReadCloser, error) {
	log.WithFields(log.Fields{"b": b, "startPosition": startPosition}).Debug("azureBlob::azureBlob::Read called")
	return b.client.GetBlob(b.path, b.name)
}

func (b *azureBlob) Write() (io.WriteCloser, error) {
	log.WithFields(log.Fields{"b": b}).Debug("azureBlob::azureBlob::Write called")
	return NewBlockBlobWriter(b)
}

func (b *azureBlob) Clone() fs.File {
	return &azureBlob{
		name:    b.name,
		path:    b.path,
		size:    b.size,
		modTime: b.modTime,
		mode:    b.mode,
		client:  b.client,
	}
}

func (b azureBlob) Delete() error {
	return b.client.DeleteBlob(b.path, b.name, nil)
}
<|endoftext|>


<commit_before>// Copyright (C) 2014 Daniel Harrison

package hfile

import (
	"bytes"
	"encoding/binary"
	"encoding/hex"
	"log"
)

type Scanner struct {
	reader *Reader
	idx    int
	block  []byte
	pos    *int
	last   []byte
	OrderedOps
}

func NewScanner(r *Reader) *Scanner {
	return &Scanner{r, 0, nil, nil, nil, OrderedOps{nil}}
}

func (s *Scanner) Reset() {
	s.idx = 0
	s.block = nil
	s.pos = nil
	s.ResetState()
}

func (s *Scanner) blockFor(key []byte) ([]byte, error, bool) {
	err := s.CheckIfKeyOutOfOrder(key)
	if err != nil {
		return nil, err, false
	}

	if s.reader.index[s.idx].IsAfter(key) {
		if s.reader.debug {
			log.Printf("[Scanner.blockFor] curBlock after key %s (cur: %d, start: %s)\n",
				hex.EncodeToString(key),
				s.idx,
				hex.EncodeToString(s.reader.index[s.idx].firstKeyBytes),
			)
		}
		return nil, nil, false
	}

	idx := s.reader.FindBlock(s.idx, key)
	if s.reader.debug {
		log.Printf("[Scanner.blockFor] findBlock (key: %s) picked %d (starts: %s). Cur: %d (starts: %s)\n",
			hex.EncodeToString(key),
			idx,
			hex.EncodeToString(s.reader.index[idx].firstKeyBytes),
			s.idx,
			hex.EncodeToString(s.reader.index[s.idx].firstKeyBytes),
		)
	}

	if idx != s.idx || s.block == nil { // need to load a new block
		data, err := s.reader.GetBlockBuf(idx, s.last)
		if err != nil {
			if s.reader.debug {
				log.Printf("[Scanner.blockFor] read err %s (key: %s, idx: %d, start: %s)\n",
					err,
					hex.EncodeToString(key),
					idx,
					hex.EncodeToString(s.reader.index[idx].firstKeyBytes),
				)
			}
			return nil, err, false
		}
		i := 8
		s.pos = &i
		s.idx = idx
		s.block = data
	} else {
		if s.reader.debug {
			log.Println("[Scanner.blockFor] Re-using current block")
		}
	}

	return s.block, nil, true
}

func (s *Scanner) GetFirst(key []byte) ([]byte, error, bool) {
	data, err, ok := s.blockFor(key)

	if !ok {
		if s.reader.debug {
			log.Printf("[Scanner.GetFirst] No Block for key: %s (err: %s, found: %s)\n", hex.EncodeToString(key), err, ok)
		}
		return nil, err, ok
	}

	if s.reader.debug {
		log.Printf("[Scanner.GetFirst] Searching Block for key: %s (pos: %d)\n", hex.EncodeToString(key), *s.pos)
	}
	value, _, found := s.getValuesFromBuffer(data, s.pos, key, true)
	if s.reader.debug {
		log.Printf("[Scanner.GetFirst] After pos pos: %d\n", *s.pos)
	}
	return value, nil, found
}

func (s *Scanner) GetAll(key []byte) ([][]byte, error) {
	data, err, ok := s.blockFor(key)

	if !ok {
		if s.reader.debug {
			log.Printf("[Scanner.GetAll] No Block for key: %s (err: %s, found: %s)\n", hex.EncodeToString(key), err, ok)
		}
		return nil, err
	}

	_, found, _ := s.getValuesFromBuffer(data, s.pos, key, false)
	return found, err
}

func (s *Scanner) getValuesFromBuffer(buf []byte, pos *int, key []byte, first bool) ([]byte, [][]byte, bool) {
	var acc [][]byte

	i := *pos

	if s.reader.debug {
		log.Printf("[Scanner.getValuesFromBuffer] buf before %d / %d\n", i, len(buf))
	}

	for len(buf)-i > 8 {
		keyLen := int(binary.BigEndian.Uint32(buf[i : i+4]))
		valLen := int(binary.BigEndian.Uint32(buf[i+4 : i+8]))

		cmp := bytes.Compare(buf[i+8:i+8+keyLen], key)

		switch {
		case cmp == 0:
			i += 8 + keyLen
			if first {
				*pos = i + valLen
				return buf[i : i+valLen], nil, true
			} else {
				acc = append(acc, buf[i:i+valLen])
				i += valLen // now on next length pair
			}
		case cmp > 0:
			*pos = i
			return nil, acc, len(acc) > 0
		default:
			i += 8 + keyLen + valLen
		}
	}

	*pos = i

	if s.reader.debug {
		log.Printf("[Scanner.getValuesFromBuffer] walked off block\n")
	}
	return nil, acc, len(acc) > 0
}
<commit_msg>alloc decompression buffer per scanner at avg block *1.5 size<commit_after>// Copyright (C) 2014 Daniel Harrison

package hfile

import (
	"bytes"
	"encoding/binary"
	"encoding/hex"
	"log"
)

type Scanner struct {
	reader *Reader
	idx    int
	block  []byte
	pos    *int
	buf    []byte
	OrderedOps
}

func NewScanner(r *Reader) *Scanner {
	var buf []byte
	if r.header.compressionCodec > CompressionNone {
		buf = make([]byte, int(float64(r.header.totalUncompressedDataBytes/uint64(len(r.index)))*1.5))
	}
	return &Scanner{r, 0, nil, nil, buf, OrderedOps{nil}}
}

func (s *Scanner) Reset() {
	s.idx = 0
	s.block = nil
	s.pos = nil
	s.ResetState()
}

func (s *Scanner) blockFor(key []byte) ([]byte, error, bool) {
	err := s.CheckIfKeyOutOfOrder(key)
	if err != nil {
		return nil, err, false
	}

	if s.reader.index[s.idx].IsAfter(key) {
		if s.reader.debug {
			log.Printf("[Scanner.blockFor] curBlock after key %s (cur: %d, start: %s)\n",
				hex.EncodeToString(key),
				s.idx,
				hex.EncodeToString(s.reader.index[s.idx].firstKeyBytes),
			)
		}
		return nil, nil, false
	}

	idx := s.reader.FindBlock(s.idx, key)
	if s.reader.debug {
		log.Printf("[Scanner.blockFor] findBlock (key: %s) picked %d (starts: %s). Cur: %d (starts: %s)\n",
			hex.EncodeToString(key),
			idx,
			hex.EncodeToString(s.reader.index[idx].firstKeyBytes),
			s.idx,
			hex.EncodeToString(s.reader.index[s.idx].firstKeyBytes),
		)
	}

	if idx != s.idx || s.block == nil { // need to load a new block
		data, err := s.reader.GetBlockBuf(idx, s.buf)
		if err != nil {
			if s.reader.debug {
				log.Printf("[Scanner.blockFor] read err %s (key: %s, idx: %d, start: %s)\n",
					err,
					hex.EncodeToString(key),
					idx,
					hex.EncodeToString(s.reader.index[idx].firstKeyBytes),
				)
			}
			return nil, err, false
		}
		i := 8
		s.pos = &i
		s.idx = idx
		s.block = data
	} else {
		if s.reader.debug {
			log.Println("[Scanner.blockFor] Re-using current block")
		}
	}

	return s.block, nil, true
}

func (s *Scanner) GetFirst(key []byte) ([]byte, error, bool) {
	data, err, ok := s.blockFor(key)

	if !ok {
		if s.reader.debug {
			log.Printf("[Scanner.GetFirst] No Block for key: %s (err: %s, found: %s)\n", hex.EncodeToString(key), err, ok)
		}
		return nil, err, ok
	}

	if s.reader.debug {
		log.Printf("[Scanner.GetFirst] Searching Block for key: %s (pos: %d)\n", hex.EncodeToString(key), *s.pos)
	}
	value, _, found := s.getValuesFromBuffer(data, s.pos, key, true)
	if s.reader.debug {
		log.Printf("[Scanner.GetFirst] After pos pos: %d\n", *s.pos)
	}
	return value, nil, found
}

func (s *Scanner) GetAll(key []byte) ([][]byte, error) {
	data, err, ok := s.blockFor(key)

	if !ok {
		if s.reader.debug {
			log.Printf("[Scanner.GetAll] No Block for key: %s (err: %s, found: %s)\n", hex.EncodeToString(key), err, ok)
		}
		return nil, err
	}

	_, found, _ := s.getValuesFromBuffer(data, s.pos, key, false)
	return found, err
}

func (s *Scanner) getValuesFromBuffer(buf []byte, pos *int, key []byte, first bool) ([]byte, [][]byte, bool) {
	var acc [][]byte

	i := *pos

	if s.reader.debug {
		log.Printf("[Scanner.getValuesFromBuffer] buf before %d / %d\n", i, len(buf))
	}

	for len(buf)-i > 8 {
		keyLen := int(binary.BigEndian.Uint32(buf[i : i+4]))
		valLen := int(binary.BigEndian.Uint32(buf[i+4 : i+8]))

		cmp := bytes.Compare(buf[i+8:i+8+keyLen], key)

		switch {
		case cmp == 0:
			i += 8 + keyLen
			if first {
				*pos = i + valLen
				return buf[i : i+valLen], nil, true
			} else {
				acc = append(acc, buf[i:i+valLen])
				i += valLen // now on next length pair
			}
		case cmp > 0:
			*pos = i
			return nil, acc, len(acc) > 0
		default:
			i += 8 + keyLen + valLen
		}
	}

	*pos = i

	if s.reader.debug {
		log.Printf("[Scanner.getValuesFromBuffer] walked off block\n")
	}
	return nil, acc, len(acc) > 0
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"regexp"

	"github.com/PuerkitoBio/goquery"
)

var idFromURL, _ = regexp.Compile("/(\\d+)$")

// ScrapeAds returns a list of ads from muusikoiden.net
func ScrapeAds() []Ad {
	doc, err := goquery.NewDocument("https://muusikoiden.net/tori/?category=0")
	if err != nil {
		log.Fatal(err)
	}

	elements := doc.Find("td.tori_title")

	ads := make([]Ad, elements.Length())

	elements.Each(func(i int, titleContainer *goquery.Selection) {
		category := titleContainer.Find("b").Text()
		link := titleContainer.Find("a")
		title := link.Text()
		path, _ := link.Attr("href")
		url := "https://muusikoiden.net" + path
		id := idFromURL.FindStringSubmatch(path)[1]

		descriptionContainer := titleContainer.Parent().Siblings().Find("font.msg")
		description := descriptionContainer.Text()
		price := descriptionContainer.SiblingsFiltered("p").Text()

		ad := Ad{id, category, title, url, description, price}
		ads[i] = ad
	})

	return ads
}
<commit_msg>Remove colon from category<commit_after>package main

import (
	"log"
	"regexp"
	"strings"

	"github.com/PuerkitoBio/goquery"
)

var idFromURL, _ = regexp.Compile("/(\\d+)$")

// ScrapeAds returns a list of ads from muusikoiden.net
func ScrapeAds() []Ad {
	doc, err := goquery.NewDocument("https://muusikoiden.net/tori/?category=0")
	if err != nil {
		log.Fatal(err)
	}

	elements := doc.Find("td.tori_title")

	ads := make([]Ad, elements.Length())

	elements.Each(func(i int, titleContainer *goquery.Selection) {
		category := strings.Replace(titleContainer.Find("b").Text(), ":", "", -1)
		link := titleContainer.Find("a")
		title := link.Text()
		path, _ := link.Attr("href")
		url := "https://muusikoiden.net" + path
		id := idFromURL.FindStringSubmatch(path)[1]

		descriptionContainer := titleContainer.Parent().Siblings().Find("font.msg")
		description := descriptionContainer.Text()
		price := descriptionContainer.SiblingsFiltered("p").Text()

		ad := Ad{id, category, title, url, description, price}
		ads[i] = ad
	})

	return ads
}
<|endoftext|>


<commit_before>// Copyright 2015 Alex Browne.  All rights reserved.
// Use of this source code is governed by the MIT
// license, which can be found in the LICENSE file.

// File scripts.go contains code related to lua scripts,
// including parsing the scripts in the scripts folder and
// wrapper functions which offer type safety for using them.

package zoom

import (
	"github.com/garyburd/redigo/redis"
	"io/ioutil"
	"os"
	"path/filepath"
)

var (
	deleteModelsBySetIdsScript      *redis.Script
	deleteStringIndexScript         *redis.Script
	extractIdsFromFieldIndexScript  *redis.Script
	extractIdsFromStringIndexScript *redis.Script
)

var (
	scriptsPath = filepath.Join(os.Getenv("GOPATH"), "src", "github.com", "albrow", "zoom", "scripts")
)

// initScripts will parse all the lua script files in scriptsPath and assign them
// to the variables above. It must be run before any scripts are executed.
func initScripts() error {
	scriptsToParse := []struct {
		script   **redis.Script
		filename string
		keyCount int
	}{
		{
			script:   &deleteModelsBySetIdsScript,
			filename: "delete_models_by_set_ids.lua",
			keyCount: 1,
		},
		{
			script:   &deleteStringIndexScript,
			filename: "delete_string_index.lua",
			keyCount: 0,
		},
		{
			script:   &extractIdsFromFieldIndexScript,
			filename: "extract_ids_from_field_index.lua",
			keyCount: 2,
		},
		{
			script:   &extractIdsFromStringIndexScript,
			filename: "extract_ids_from_string_index.lua",
			keyCount: 2,
		},
	}
	for _, s := range scriptsToParse {
		// Parse the file corresponding to this script
		fullPath := filepath.Join(scriptsPath, s.filename)
		src, err := ioutil.ReadFile(fullPath)
		if err != nil {
			return err
		}
		// Set the value of the script pointer
		(*s.script) = redis.NewScript(s.keyCount, string(src))
	}
	return nil
}

// deleteModelsBySetIds is a small function wrapper around deleteModelsBySetIdsScript.
// It offers some type safety and helps make sure the arguments you pass through to the are correct.
// The script will delete the models corresponding to the ids in the given set and return the number
// of models that were deleted. You can use the handler to capture the return value.
func (t *Transaction) deleteModelsBySetIds(setKey string, modelName string, handler ReplyHandler) {
	t.Script(deleteModelsBySetIdsScript, redis.Args{setKey, modelName}, handler)
}

// deleteStringIndex is a small function wrapper around deleteStringIndexScript.
// It offers some type safety and helps make sure the arguments you pass through to the are correct.
// The script will atomically remove the existing index, if any, on the given field name.
func (t *Transaction) deleteStringIndex(modelName, modelId, fieldName string) {
	t.Script(deleteStringIndexScript, redis.Args{modelName, modelId, fieldName}, nil)
}

// extractIdsFromFieldIndex is a small function wrapper around extractIdsFromFieldIndexScript.
// It offers some type safety and helps make sure the arguments you pass through to the are correct.
// The script will get all the ids from setKey using ZRANGEBYSCORE with the given min and max, and then
// store them in a sorted set identified by destKey.
func (t *Transaction) extractIdsFromFieldIndex(setKey string, destKey string, min interface{}, max interface{}) {
	t.Script(extractIdsFromFieldIndexScript, redis.Args{setKey, destKey, min, max}, nil)
}

// extractIdsFromStringIndex is a small function wrapper around extractIdsFromStringIndexScript.
// It offers some type safety and helps make sure the arguments you pass through to the are correct.
// The script will extract the ids from setKey using ZRANGEBYLEX with the given min and max, and then
// store them in a sorted set identified by destKey.
func (t *Transaction) extractIdsFromStringIndex(setKey, destKey, min, max string) {
	t.Script(extractIdsFromStringIndexScript, redis.Args{setKey, destKey, min, max}, nil)
}
<commit_msg>Attempt to fix script path problems.<commit_after>// Copyright 2015 Alex Browne.  All rights reserved.
// Use of this source code is governed by the MIT
// license, which can be found in the LICENSE file.

// File scripts.go contains code related to lua scripts,
// including parsing the scripts in the scripts folder and
// wrapper functions which offer type safety for using them.

package zoom

import (
	"github.com/garyburd/redigo/redis"
	"go/build"
	"io/ioutil"
	"path/filepath"
)

var (
	deleteModelsBySetIdsScript      *redis.Script
	deleteStringIndexScript         *redis.Script
	extractIdsFromFieldIndexScript  *redis.Script
	extractIdsFromStringIndexScript *redis.Script
)

var (
	scriptsPath string
)

// initScripts will parse all the lua script files in scriptsPath and assign them
// to the variables above. It must be run before any scripts are executed.
func initScripts() error {
	pkg, err := build.Import("github.com/albrow/zoom", "", build.FindOnly)
	if err != nil {
		return err
	}
	scriptsPath = filepath.Join(pkg.Dir, "scripts")
	scriptsToParse := []struct {
		script   **redis.Script
		filename string
		keyCount int
	}{
		{
			script:   &deleteModelsBySetIdsScript,
			filename: "delete_models_by_set_ids.lua",
			keyCount: 1,
		},
		{
			script:   &deleteStringIndexScript,
			filename: "delete_string_index.lua",
			keyCount: 0,
		},
		{
			script:   &extractIdsFromFieldIndexScript,
			filename: "extract_ids_from_field_index.lua",
			keyCount: 2,
		},
		{
			script:   &extractIdsFromStringIndexScript,
			filename: "extract_ids_from_string_index.lua",
			keyCount: 2,
		},
	}
	for _, s := range scriptsToParse {
		// Parse the file corresponding to this script
		fullPath := filepath.Join(scriptsPath, s.filename)
		src, err := ioutil.ReadFile(fullPath)
		if err != nil {
			return err
		}
		// Set the value of the script pointer
		(*s.script) = redis.NewScript(s.keyCount, string(src))
	}
	return nil
}

// deleteModelsBySetIds is a small function wrapper around deleteModelsBySetIdsScript.
// It offers some type safety and helps make sure the arguments you pass through to the are correct.
// The script will delete the models corresponding to the ids in the given set and return the number
// of models that were deleted. You can use the handler to capture the return value.
func (t *Transaction) deleteModelsBySetIds(setKey string, modelName string, handler ReplyHandler) {
	t.Script(deleteModelsBySetIdsScript, redis.Args{setKey, modelName}, handler)
}

// deleteStringIndex is a small function wrapper around deleteStringIndexScript.
// It offers some type safety and helps make sure the arguments you pass through to the are correct.
// The script will atomically remove the existing index, if any, on the given field name.
func (t *Transaction) deleteStringIndex(modelName, modelId, fieldName string) {
	t.Script(deleteStringIndexScript, redis.Args{modelName, modelId, fieldName}, nil)
}

// extractIdsFromFieldIndex is a small function wrapper around extractIdsFromFieldIndexScript.
// It offers some type safety and helps make sure the arguments you pass through to the are correct.
// The script will get all the ids from setKey using ZRANGEBYSCORE with the given min and max, and then
// store them in a sorted set identified by destKey.
func (t *Transaction) extractIdsFromFieldIndex(setKey string, destKey string, min interface{}, max interface{}) {
	t.Script(extractIdsFromFieldIndexScript, redis.Args{setKey, destKey, min, max}, nil)
}

// extractIdsFromStringIndex is a small function wrapper around extractIdsFromStringIndexScript.
// It offers some type safety and helps make sure the arguments you pass through to the are correct.
// The script will extract the ids from setKey using ZRANGEBYLEX with the given min and max, and then
// store them in a sorted set identified by destKey.
func (t *Transaction) extractIdsFromStringIndex(setKey, destKey, min, max string) {
	t.Script(extractIdsFromStringIndexScript, redis.Args{setKey, destKey, min, max}, nil)
}
<|endoftext|>


<commit_before>// Library for all functions used in Yieldbot alert handlers and dashboard generators
//
// LICENSE:
//   Copyright 2015 Yieldbot. <devops@yieldbot.com>
//   Released under the MIT License; see LICENSE
//   for details.

// Package dracky implements common data structures and functions for Yieldbot monitoring alerts and dashboards
package dracky

import (
	"encoding/json"
	"github.com/yieldbot/dhuran"
	"io/ioutil"
	"os"
	"strings"
)

// Generate a simple string for use by elasticsearch and internal logging of all monitoring alerts.
func Event_name(client string, check string) string {
	return client + "_" + check
}

// Set the correct device that is being monitored. In the case of snmp trap collection, containers, or applicance
// monitoring the device running the sensu-client may not be the device actually being monitored.
func (e Sensu_Event) Acquire_monitored_instance() string {
	var monitored_instance string
	if e.Check.Source != "" {
		monitored_instance = e.Check.Source
	} else {
		monitored_instance = e.Client.Name
	}
	return monitored_instance
}

// func Set_time(t int) string {
//
// 	timeStamp := time.Unix(unixIntValue, 0)
// 	timestamp = time.Unix(timestamp, 0).Format(time.RFC822Z)
//
// }

// Set the environment that the machine is running in based upon values
// dropped via Oahi during the Chef run.
func Define_sensu_env(env string) string {
	switch env {
	case "prd":
		return "Prod "
	case "dev":
		return "Dev "
	case "stg":
		return "Stg "
	case "vagrant":
		return "Vagrant "
	default:
		return "Test "
	}
}

// Convert the check result status from an integer to a string.
func Define_status(status int) string {
	switch status {
	case 0:
		return "OK"
	case 1:
		return "WARNING"
	case 2:
		return "CRITICAL"
	case 3:
		return "UNKNOWN"
	case 126:
		return "PERMISSION DENIED"
	case 127:
		return "CONFIG ERROR"
	default:
		return "UNKNOWN"
	}
}

// Creates a monitor name that is easliy searchable in ES using different
// levels of granularity.
func Create_check_name(check string) string {
	// I want something like check.cpu.user so that I can filter easily from specific to generic
	// check-process-ntp-offset --> check.process.ntp.offset
	fmtd_check := strings.Replace(check, "-", ".", -1)
	return fmtd_check
}

// Calculate how long a monitor has been in a given state.
func Define_check_state_duration() string {
	return " "
}

// Read in the environment details provided by Oahi and drop it into a staticly defined struct.
func Set_sensu_env() *Env_Details {
	env_file, err := ioutil.ReadFile(ENVIRONMENT_FILE)
	if err != nil {
		dhuran.Check(err)
	}

	var env_details Env_Details
	err = json.Unmarshal(env_file, &env_details)
	if err != nil {
		dhuran.Check(err)
	}
	return &env_details
}

// Read in the check result generated by Snesu via stdin and drop it into a staticaly defined struct.
func (e Sensu_Event) Acquire_sensu_event() *Sensu_Event {
	results, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		dhuran.Check(err)
	}
	err = json.Unmarshal(results, &e)
	if err != nil {
		dhuran.Check(err)
	}
	return &e
}
<commit_msg>cleanup<commit_after>// Library for all functions used in Yieldbot alert handlers and dashboard generators
//
// LICENSE:
//   Copyright 2015 Yieldbot. <devops@yieldbot.com>
//   Released under the MIT License; see LICENSE
//   for details.

// Package dracky implements common data structures and functions for Yieldbot monitoring alerts and dashboards
package dracky

import (
	"encoding/json"
	"github.com/yieldbot/dhuran"
	"io/ioutil"
	"os"
	"strings"
)

// Generate a simple string for use by elasticsearch and internal logging of all monitoring alerts.
func Event_name(client string, check string) string {
	return client + "_" + check
}

// Set the correct device that is being monitored. In the case of snmp trap collection, containers, or applicance
// monitoring the device running the sensu-client may not be the device actually being monitored.
func (e Sensu_Event) Acquire_monitored_instance() string {
	var monitored_instance string
	if e.Check.Source != "" {
		monitored_instance = e.Check.Source
	} else {
		monitored_instance = e.Client.Name
	}
	return monitored_instance
}

// func Set_time(t int) string {
//
// 	timeStamp := time.Unix(unixIntValue, 0)
// 	timestamp = time.Unix(timestamp, 0).Format(time.RFC822Z)
//
// }

// Set the environment that the machine is running in based upon values
// dropped via Oahi during the Chef run.
func Define_sensu_env(env string) string {
	switch env {
	case "prd":
		return "Prod "
	case "dev":
		return "Dev "
	case "stg":
		return "Stg "
	case "vagrant":
		return "Vagrant "
	default:
		return "Test "
	}
}

// Convert the check result status from an integer to a string.
func Define_status(status int) string {
	switch status {
	case 0:
		return "OK"
	case 1:
		return "WARNING"
	case 2:
		return "CRITICAL"
	case 3:
		return "UNKNOWN"
	case 126:
		return "PERMISSION DENIED"
	case 127:
		return "CONFIG ERROR"
	default:
		return "UNKNOWN"
	}
}

// Creates a monitor name that is easliy searchable in ES using different
// levels of granularity.
func Create_check_name(check string) string {
	fmtd_check := strings.Replace(check, "-", ".", -1)
	return fmtd_check
}

// Calculate how long a monitor has been in a given state.
func Define_check_state_duration() string {
	return " "
}

// Read in the environment details provided by Oahi and drop it into a staticly defined struct.
func Set_sensu_env() *Env_Details {
	env_file, err := ioutil.ReadFile(ENVIRONMENT_FILE)
	if err != nil {
		dhuran.Check(err)
	}

	var env_details Env_Details
	err = json.Unmarshal(env_file, &env_details)
	if err != nil {
		dhuran.Check(err)
	}
	return &env_details
}

// Read in the check result generated by Snesu via stdin and drop it into a staticaly defined struct.
func (e Sensu_Event) Acquire_sensu_event() *Sensu_Event {
	results, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		dhuran.Check(err)
	}
	err = json.Unmarshal(results, &e)
	if err != nil {
		dhuran.Check(err)
	}
	return &e
}
<|endoftext|>


<commit_before>package configparser

import "strings"

type Section struct {
	Name    string
	options Dict
	lookup  Dict
}

func (s *Section) Add(key, value string) error {
	lookupKey := s.safeKey(key)

	s.options[key] = s.safeValue(value)
	s.lookup[lookupKey] = key
	return nil
}

func (s *Section) Get(key string) (string, error) {
	lookupKey, present := s.lookup[s.safeKey(key)]
	if !present {
		return "", getNoOptionError(s.Name, key)
	}
	if value, present := s.options[lookupKey]; present {
		return value, nil
	}
	return "", getNoOptionError(s.Name, key)
}

func (s *Section) Options() []string {
	return s.options.Keys()
}

func (s *Section) Items() Dict {
	items := make(Dict)
	for _, option := range s.Options() {
		items[option] = s.options[option]
	}
	return items
}

func (s *Section) safeValue(in string) string {
	// Same as safeKey for now.
	return s.safeKey(in)
}

func (s *Section) safeKey(in string) string {
	return strings.ToLower(strings.TrimSpace(in))
}

func newSection(name string) *Section {
	return &Section{
		Name:    name,
		options: make(Dict),
		lookup:  make(Dict),
	}
}
<commit_msg>Items() should just return the options<commit_after>package configparser

import "strings"

type Section struct {
	Name    string
	options Dict
	lookup  Dict
}

func (s *Section) Add(key, value string) error {
	lookupKey := s.safeKey(key)

	s.options[key] = s.safeValue(value)
	s.lookup[lookupKey] = key
	return nil
}

func (s *Section) Get(key string) (string, error) {
	lookupKey, present := s.lookup[s.safeKey(key)]
	if !present {
		return "", getNoOptionError(s.Name, key)
	}
	if value, present := s.options[lookupKey]; present {
		return value, nil
	}
	return "", getNoOptionError(s.Name, key)
}

func (s *Section) Options() []string {
	return s.options.Keys()
}

func (s *Section) Items() Dict {
	return s.options
}

func (s *Section) safeValue(in string) string {
	// Same as safeKey for now.
	return s.safeKey(in)
}

func (s *Section) safeKey(in string) string {
	return strings.ToLower(strings.TrimSpace(in))
}

func newSection(name string) *Section {
	return &Section{
		Name:    name,
		options: make(Dict),
		lookup:  make(Dict),
	}
}
<|endoftext|>


<commit_before>package paginator

import (
	"gnd.la/html"
	"html/template"
	"strconv"
)

var (
	DefaultOffset = 5
)

type Paginator struct {
	Base    string
	Current int
	Count   int
	Offset  int
	Pager   Pager
}

func (p *Paginator) pageHref(page int) string {
	return p.Pager.Href(p.Base, page)
}

func (p *Paginator) appendNode(parent, cur *html.Node, page, flags int) {
	node := p.Pager.Node(cur, page, flags)
	if node != nil {
		parent.AppendChild(node)
	}
}

func (p *Paginator) Render() template.HTML {
	root := p.Pager.Root()
	parent := root
	for parent.Children != nil {
		parent = parent.LastChild()
	}
	flags := PREVIOUS | DISABLED
	prev := &html.Node{Tag: "a", Attrs: html.Attrs{}}
	if p.Current > 1 {
		prev.Attrs["href"] = p.pageHref(p.Current - 1)
		flags &= ^DISABLED
	}
	p.appendNode(parent, prev, p.Current-1, flags)
	left := p.Current - p.Offset
	if left < 1 {
		left = 1
	}
	if left > 1 {
		p.appendNode(parent, &html.Node{Tag: "a"}, 0, SEPARATOR)
	}
	for ; left < p.Current; left++ {
		node := &html.Node{Tag: "a", Children: html.Text(strconv.Itoa(left)), Attrs: html.Attrs{"href": p.pageHref(left)}}
		p.appendNode(parent, node, left, 0)
	}
	p.appendNode(parent, &html.Node{Tag: "a", Children: html.Text(strconv.Itoa(p.Current))}, p.Current, CURRENT)
	right := p.Current + p.Offset
	if right > p.Count {
		right = p.Count
	}
	for jj := p.Current + 1; jj <= right; jj++ {
		node := &html.Node{Tag: "a", Children: html.Text(strconv.Itoa(jj)), Attrs: html.Attrs{"href": p.pageHref(jj)}}
		p.appendNode(parent, node, jj, 0)
	}
	if right < p.Count {
		p.appendNode(parent, &html.Node{Tag: "a"}, 0, SEPARATOR)
	}
	flags = NEXT | DISABLED
	next := &html.Node{Tag: "a", Attrs: html.Attrs{}}
	if p.Current < p.Count {
		next.Attrs["href"] = p.pageHref(p.Current + 1)
		flags &= ^DISABLED
	}
	p.appendNode(parent, next, p.Current+1, flags)
	return root.HTML()
}

func New(base string, current, count int, pager Pager) *Paginator {
	return &Paginator{
		Base:    base,
		Current: current,
		Count:   count,
		Offset:  DefaultOffset,
		Pager:   pager,
	}
}
<commit_msg>Add support for always showing first/last page<commit_after>package paginator

import (
	"gnd.la/html"
	"html/template"
	"strconv"
)

var (
	DefaultOffset = 5
)

type Paginator struct {
	Base            string
	Current         int
	Count           int
	Offset          int
	Pager           Pager
	AlwaysShowFirst bool
	AlwaysShowLast  bool
}

func (p *Paginator) pageHref(page int) string {
	return p.Pager.Href(p.Base, page)
}

func (p *Paginator) appendNode(parent, cur *html.Node, page, flags int) {
	node := p.Pager.Node(cur, page, flags)
	if node != nil {
		parent.AppendChild(node)
	}
}

func (p *Paginator) appendPageNode(parent *html.Node, page int) {
	node := &html.Node{
		Tag:      "a",
		Children: html.Text(strconv.Itoa(page)),
		Attrs:    html.Attrs{"href": p.pageHref(page)},
	}
	p.appendNode(parent, node, page, 0)
}

func (p *Paginator) Render() template.HTML {
	root := p.Pager.Root()
	parent := root
	for parent.Children != nil {
		parent = parent.LastChild()
	}
	flags := PREVIOUS | DISABLED
	prev := &html.Node{Tag: "a", Attrs: html.Attrs{}}
	if p.Current > 1 {
		prev.Attrs["href"] = p.pageHref(p.Current - 1)
		flags &= ^DISABLED
	}
	p.appendNode(parent, prev, p.Current-1, flags)
	left := p.Current - p.Offset
	if left < 1 {
		left = 1
	}
	if left > 1 {
		cur := -1
		if p.AlwaysShowFirst {
			for cur = 1; cur < left && cur <= p.Offset; cur++ {
				p.appendPageNode(parent, cur)
			}
		}
		if left > cur {
			p.appendNode(parent, &html.Node{Tag: "a"}, 0, SEPARATOR)
		}
	}
	for ; left < p.Current; left++ {
		p.appendPageNode(parent, left)
	}
	p.appendNode(parent, &html.Node{Tag: "a", Children: html.Text(strconv.Itoa(p.Current))}, p.Current, CURRENT)
	right := p.Current + p.Offset
	if right > p.Count {
		right = p.Count
	}
	for jj := p.Current + 1; jj <= right; jj++ {
		p.appendPageNode(parent, jj)
	}
	if right < p.Count {
		if p.AlwaysShowLast {
			cur := p.Count - p.Offset + 1
			if cur <= right {
				cur = right + 1
			} else if cur > right+1 {
				p.appendNode(parent, &html.Node{Tag: "a"}, 0, SEPARATOR)
			}
			for ; cur <= p.Count; cur++ {
				p.appendPageNode(parent, cur)
			}
		} else {
			p.appendNode(parent, &html.Node{Tag: "a"}, 0, SEPARATOR)
		}
	}
	flags = NEXT | DISABLED
	next := &html.Node{Tag: "a", Attrs: html.Attrs{}}
	if p.Current < p.Count {
		next.Attrs["href"] = p.pageHref(p.Current + 1)
		flags &= ^DISABLED
	}
	p.appendNode(parent, next, p.Current+1, flags)
	return root.HTML()
}

func New(base string, current, count int, pager Pager) *Paginator {
	return &Paginator{
		Base:    base,
		Current: current,
		Count:   count,
		Offset:  DefaultOffset,
		Pager:   pager,
	}
}
<|endoftext|>


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

package gcs

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"strings"
	"testing"
	"testing/iotest"
	"time"

	"golang.org/x/net/context"

	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/oglemock"
	. "github.com/jacobsa/ogletest"
)

func TestRetry(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func contentsAre(s string) Matcher {
	pred := func(c interface{}) (err error) {
		// Convert.
		req, ok := c.(*CreateObjectRequest)
		if !ok {
			err = fmt.Errorf("which has type %T", c)
			return
		}

		// Read.
		contents, err := ioutil.ReadAll(req.Contents)
		if err != nil {
			err = fmt.Errorf("whose contents cannot be read: %v", err)
			return
		}

		// Compare.
		if string(contents) != s {
			err = errors.New("whose contents don't match")
			return
		}

		return
	}

	return NewMatcher(pred, "has the specified contents")
}

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type retryBucketTest struct {
	ctx     context.Context
	wrapped MockBucket
	bucket  Bucket
}

func (t *retryBucketTest) SetUp(ti *TestInfo) {
	t.ctx = ti.Ctx
	t.wrapped = NewMockBucket(ti.MockController, "wrapped")
	t.bucket = newRetryBucket(time.Second, t.wrapped)
}

////////////////////////////////////////////////////////////////////////
// CreateObject
////////////////////////////////////////////////////////////////////////

type RetryBucket_CreateObjectTest struct {
	retryBucketTest

	req CreateObjectRequest
	obj *Object
}

func init() { RegisterTestSuite(&RetryBucket_CreateObjectTest{}) }

func (t *RetryBucket_CreateObjectTest) call() (err error) {
	t.obj, err = t.bucket.CreateObject(t.ctx, &t.req)
	return
}

func (t *RetryBucket_CreateObjectTest) ErrorReading() {
	var err error

	// Pass in a reader that will return an error.
	t.req.Contents = ioutil.NopCloser(
		iotest.OneByteReader(
			iotest.TimeoutReader(
				strings.NewReader("foobar"))))

	// Call
	err = t.call()

	ExpectThat(err, Error(HasSubstr("ReadAll")))
	ExpectThat(err, Error(HasSubstr("timeout")))
}

func (t *RetryBucket_CreateObjectTest) CallsWrapped() {
	const expected = "taco"

	// Request
	t.req.Contents = ioutil.NopCloser(strings.NewReader(expected))

	// Wrapped
	ExpectCall(t.wrapped, "CreateObject")(Any(), contentsAre(expected)).
		WillOnce(Return(nil, errors.New("")))

	// Call
	t.call()
}

func (t *RetryBucket_CreateObjectTest) Successful() {
	var err error

	// Request
	t.req.Contents = ioutil.NopCloser(strings.NewReader(""))

	// Wrapped
	expected := &Object{}
	ExpectCall(t.wrapped, "CreateObject")(Any(), Any()).
		WillOnce(Return(expected, nil))

	// Call
	err = t.call()

	AssertEq(nil, err)
	ExpectEq(expected, t.obj)
}

func (t *RetryBucket_CreateObjectTest) ShouldNotRetry() {
	var err error

	// Request
	t.req.Contents = ioutil.NopCloser(strings.NewReader(""))

	// Wrapped
	expected := errors.New("taco")
	ExpectCall(t.wrapped, "CreateObject")(Any(), Any()).
		WillOnce(Return(nil, expected))

	// Call
	err = t.call()

	ExpectEq(expected, err)
}

func (t *RetryBucket_CreateObjectTest) CallsWrappedForRetry() {
	const expected = "taco"

	// Request
	t.req.Contents = ioutil.NopCloser(strings.NewReader(expected))

	// Wrapped
	retryable := io.ErrUnexpectedEOF

	ExpectCall(t.wrapped, "CreateObject")(Any(), contentsAre(expected)).
		WillOnce(Return(nil, retryable)).
		WillOnce(Return(nil, errors.New("")))

	// Call
	t.call()
}

func (t *RetryBucket_CreateObjectTest) RetrySuccessful() {
	var err error

	// Request
	t.req.Contents = ioutil.NopCloser(strings.NewReader(""))

	// Wrapped
	retryable := io.ErrUnexpectedEOF
	expected := &Object{}

	ExpectCall(t.wrapped, "CreateObject")(Any(), Any()).
		WillOnce(Return(nil, retryable)).
		WillOnce(Return(expected, nil))

	// Call
	err = t.call()

	AssertEq(nil, err)
	ExpectEq(expected, t.obj)
}
<commit_msg>Fix retry_test.go failure<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package gcs

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"strings"
	"testing"
	"testing/iotest"
	"time"

	"golang.org/x/net/context"

	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/oglemock"
	. "github.com/jacobsa/ogletest"
)

func TestRetry(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func contentsAre(s string) Matcher {
	pred := func(c interface{}) (err error) {
		// Convert.
		req, ok := c.(*CreateObjectRequest)
		if !ok {
			err = fmt.Errorf("which has type %T", c)
			return
		}

		// Read.
		contents, err := ioutil.ReadAll(req.Contents)
		if err != nil {
			err = fmt.Errorf("whose contents cannot be read: %v", err)
			return
		}

		// Compare.
		if string(contents) != s {
			err = errors.New("whose contents don't match")
			return
		}

		return
	}

	return NewMatcher(pred, "has the specified contents")
}

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type retryBucketTest struct {
	ctx     context.Context
	wrapped MockBucket
	bucket  Bucket
}

func (t *retryBucketTest) SetUp(ti *TestInfo) {
	t.ctx = ti.Ctx
	t.wrapped = NewMockBucket(ti.MockController, "wrapped")
	t.bucket = newRetryBucket(time.Second, t.wrapped)
}

////////////////////////////////////////////////////////////////////////
// CreateObject
////////////////////////////////////////////////////////////////////////

type RetryBucket_CreateObjectTest struct {
	retryBucketTest

	req CreateObjectRequest
	obj *Object
}

func init() { RegisterTestSuite(&RetryBucket_CreateObjectTest{}) }

func (t *RetryBucket_CreateObjectTest) call() (err error) {
	t.obj, err = t.bucket.CreateObject(t.ctx, &t.req)
	return
}

func (t *RetryBucket_CreateObjectTest) ErrorReading() {
	var err error

	// Pass in a reader that will return an error.
	t.req.Contents = ioutil.NopCloser(
		iotest.OneByteReader(
			iotest.TimeoutReader(
				strings.NewReader("foobar"))))

	// Call
	err = t.call()

	ExpectThat(err, Error(HasSubstr("ReadAll")))
	ExpectThat(err, Error(HasSubstr("timeout")))
}

func (t *RetryBucket_CreateObjectTest) CallsWrapped() {
	const expected = "taco"

	// Request
	t.req.Contents = ioutil.NopCloser(strings.NewReader(expected))

	// Wrapped
	ExpectCall(t.wrapped, "CreateObject")(Any(), contentsAre(expected)).
		WillOnce(Return(nil, errors.New("")))

	// Call
	t.call()
}

func (t *RetryBucket_CreateObjectTest) Successful() {
	var err error

	// Request
	t.req.Contents = ioutil.NopCloser(strings.NewReader(""))

	// Wrapped
	expected := &Object{}
	ExpectCall(t.wrapped, "CreateObject")(Any(), Any()).
		WillOnce(Return(expected, nil))

	// Call
	err = t.call()

	AssertEq(nil, err)
	ExpectEq(expected, t.obj)
}

func (t *RetryBucket_CreateObjectTest) ShouldNotRetry() {
	var err error

	// Request
	t.req.Contents = ioutil.NopCloser(strings.NewReader(""))

	// Wrapped
	expected := errors.New("taco")
	ExpectCall(t.wrapped, "CreateObject")(Any(), Any()).
		WillOnce(Return(nil, expected))

	// Call
	err = t.call()

	ExpectTrue(errors.Is(err, expected))
}

func (t *RetryBucket_CreateObjectTest) CallsWrappedForRetry() {
	const expected = "taco"

	// Request
	t.req.Contents = ioutil.NopCloser(strings.NewReader(expected))

	// Wrapped
	retryable := io.ErrUnexpectedEOF

	ExpectCall(t.wrapped, "CreateObject")(Any(), contentsAre(expected)).
		WillOnce(Return(nil, retryable)).
		WillOnce(Return(nil, errors.New("")))

	// Call
	t.call()
}

func (t *RetryBucket_CreateObjectTest) RetrySuccessful() {
	var err error

	// Request
	t.req.Contents = ioutil.NopCloser(strings.NewReader(""))

	// Wrapped
	retryable := io.ErrUnexpectedEOF
	expected := &Object{}

	ExpectCall(t.wrapped, "CreateObject")(Any(), Any()).
		WillOnce(Return(nil, retryable)).
		WillOnce(Return(expected, nil))

	// Call
	err = t.call()

	AssertEq(nil, err)
	ExpectEq(expected, t.obj)
}
<|endoftext|>