cmd/core/input/input.go (63 lines of code) (raw):

/* Copyright (c) Facebook, Inc. and its affiliates. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. */ package input import ( "bufio" "fmt" "io" "os" "github.com/facebookincubator/fbender/cmd/core/errors" "github.com/facebookincubator/fbender/cmd/core/runner" "github.com/facebookincubator/fbender/log" ) // Transformer converts input line into a request. type Transformer func(string) (interface{}, error) // Modifier changes request right before sending. type Modifier func(interface{}) (interface{}, error) // NewRequestGenerator reads data from the specified input and converts it into // requests using given transformer. The lines which aren't formatted correctly // are skipped. The requests are then reused in a round-robin manner inside the // generator. If modifiers are provided they are applied to the request every // time just before being returned. func NewRequestGenerator(filename string, transformer Transformer, mods ...Modifier) (runner.RequestGenerator, error) { file, err := open(filename) if err != nil { return nil, err } defer close(file) data := parse(file, transformer) if len(data) < 1 { return nil, fmt.Errorf("%w: at least one valid input line is required", errors.ErrInvalidFormat) } return func(i int) interface{} { var err error request := data[i%len(data)] for _, mod := range mods { request, err = mod(request) if err != nil { panic(err) } } return request }, nil } // parse reads data from the specified input and converts it into requests // using given transformer. The lines which are not formatted correctly are // skipped and a warning message is printed to stderr. func parse(input io.Reader, transformer Transformer) []interface{} { requests := make([]interface{}, 0) scanner := bufio.NewScanner(input) for scanner.Scan() { line := scanner.Text() request, err := transformer(line) if err != nil { log.Errorf("Warning: Error parsing input line %q: %v\n", line, err) } else { requests = append(requests, request) } } return requests } func open(filename string) (*os.File, error) { if len(filename) == 0 { log.Errorf("Reading input lines until EOF:\n") return os.Stdin, nil } return os.Open(filename) } func close(file io.Closer) { if file == os.Stdin { return } if err := file.Close(); err != nil { log.Errorf("Warning: Error closing input file: %v\n", err) } }