script

package module
v1.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 23, 2019 License: Apache-2.0 Imports: 14 Imported by: 12

README

script

Build Status codecov GoDoc goreadme

Package script provides helper functions to write scripts.

Inspired by https://github.com/bitfield/script, with some improvements:

  • Output between streamed commands is a stream and not loaded to memory.

  • Better representation and handling of errors.

  • Proper incocation, usage and handling of stderr of custom commands.

The script chain is represented by a Stream object. While each command in the stream is abstracted by the Command struct. This library provides basic functionality, but can be extended freely.

Examples
HelloWorld

A simple "hello world" example that creats a stream and pipe it to the stdout.

// Create an "hello world" stream and use the ToStdout method to write it to stdout.
Echo("hello world").ToStdout()

Output:

hello world

Iterate

An example that shows how to iterate scanned lines.

// Stream can be any stream, in this case we have echoed 3 lines.
stream := Echo("first\nsecond\nthird")

// To iterate over the stream lines, it is better not to read it into memory and split over the
// lines, but use the `bufio.Scanner`:
defer stream.Close()
scanner := bufio.NewScanner(stream)
for scanner.Scan() {
    fmt.Println(scanner.Text())
}

Output:

first
second
third

PipeTo

An example that shows how to create custom commands using the PipeTo method with a PipeFn function.

Echo("1\n2\n3").PipeTo(func(r io.Reader) Command {
    // Create a command that sums up all numbers in input.
    //
    // In this example we create a reader function such that the whole code will fit into the
    // example function body. A more proper and readable way to do it was to create a new
    // type with a state that implements the `io.Reader` interface.

    // Use buffered reader to read lines from input.
    buf := bufio.NewReader(r)

    // Store the sum of all numbers.
    sum := 0

    // Read function reads the next line and adds it to the sum. If it gets and EOF error, it
    // writes the sum to the output and returns an EOF.
    read := func(b []byte) (int, error) {
        // Read next line from input.
        line, _, err := buf.ReadLine()

        // if EOF write sum to output.
        if err == io.EOF {
            return copy(b, append([]byte(strconv.Itoa(sum)), '\n')), io.EOF
        }
        if err != nil {
            return 0, err
        }

        // Convert the line to a number and add it to the sum.
        if i, err := strconv.Atoi(string(line)); err == nil {
            sum += i
        }

        // We don't write anything to output, so we return 0 bytes with no error.
        return 0, nil
    }

    return Command{Name: "sum", Reader: readerFn(read)}
}).ToStdout()

Output:

6


Created by goreadme

Documentation

Overview

Package script provides helper functions to write scripts.

Inspired by https://github.com/bitfield/script, with some improvements:

* Output between streamed commands is a stream and not loaded to memory.

* Better representation and handling of errors.

* Proper incocation, usage and handling of stderr of custom commands.

The script chain is represented by a (`Stream`) https://godoc.org/github.com/posener/script#Stream object. While each command in the stream is abstracted by the (`Command`) https://godoc.org/github.com/posener/script#Command struct. This library provides basic functionality, but can be extended freely.

Example (HelloWorld)

A simple "hello world" example that creats a stream and pipe it to the stdout.

// Create an "hello world" stream and use the ToStdout method to write it to stdout.
Echo("hello world").ToStdout()
Output:

hello world
Example (Iterate)

An example that shows how to iterate scanned lines.

// Stream can be any stream, in this case we have echoed 3 lines.
stream := Echo("first\nsecond\nthird")

// To iterate over the stream lines, it is better not to read it into memory and split over the
// lines, but use the `bufio.Scanner`:
defer stream.Close()
scanner := bufio.NewScanner(stream)
for scanner.Scan() {
	fmt.Println(scanner.Text())
}
Output:

first
second
third
Example (PipeTo)

An example that shows how to create custom commands using the `PipeTo` method with a `PipeFn` function.

Echo("1\n2\n3").PipeTo(func(r io.Reader) Command {
	// Create a command that sums up all numbers in input.
	//
	// In this example we create a reader function such that the whole code will fit into the
	// example function body. A more proper and readable way to do it was to create a new
	// type with a state that implements the `io.Reader` interface.

	// Use buffered reader to read lines from input.
	buf := bufio.NewReader(r)

	// Store the sum of all numbers.
	sum := 0

	// Read function reads the next line and adds it to the sum. If it gets and EOF error, it
	// writes the sum to the output and returns an EOF.
	read := func(b []byte) (int, error) {
		// Read next line from input.
		line, _, err := buf.ReadLine()

		// if EOF write sum to output.
		if err == io.EOF {
			return copy(b, append([]byte(strconv.Itoa(sum)), '\n')), io.EOF
		}
		if err != nil {
			return 0, err
		}

		// Convert the line to a number and add it to the sum.
		if i, err := strconv.Atoi(string(line)); err == nil {
			sum += i
		}

		// We don't write anything to output, so we return 0 bytes with no error.
		return 0, nil
	}

	return Command{Name: "sum", Reader: readerFn(read)}
}).ToStdout()
Output:

6

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Command

type Command struct {
	// Reader reads the output of the command.
	io.Reader
	// Closer closes the reader of the command.
	io.Closer
	// Name is the name of the command.
	Name string
	// contains filtered or unexported fields
}

Command represents a single command in a stream. A valid command must have at least a non-nil `Reader` and not empty `Name`.

func (*Command) AppendError

func (c *Command) AppendError(err error, format string, args ...interface{})

Append an error to the command.

func (Command) Close

func (c Command) Close() error

type Count

type Count struct {
	// Stream can be used to pipe the output of wc.
	Stream
	// Count the number of lines, words and chars in the input.
	Lines, Words, Chars int
}

Count represents the output of `wc` shell command.

func (Count) String

func (c Count) String() string

type Cut

type Cut struct {
	// Fileds defines which fields will be collected to the output of the command. The fields are 1
	// based (first field is 1).
	Fields []int
	// Delim is the delimited by which the fields of each line are sparated.
	Delim []byte
}

Cut is a `Modifier` that takes selected fields from each line according to a given delimiter. The default delimiter is tab.

Shell command: `cut -d<Delim> -f<Fields>`.

func (Cut) Modify

func (c Cut) Modify(line []byte) (modifed []byte, err error)

func (Cut) Name

func (c Cut) Name() string

type File

type File struct {
	// FileInfo contains information about the file.
	os.FileInfo
	// Path is the path of the file. It may be relative or absolute, depending on how the `Ls`
	// command was invoked.
	Path string
}

File contains information about a file.

type Files

type Files struct {
	Stream
	Files []File
}

Files is a stream of a list of files. A user can eigher use the file list directly or the the created stream. In the stream, each line contains a path to a file.

func Ls

func Ls(paths ...string) Files

Ls returns a stream of a list files. In the returned stream, each line will contain a path to a single file.

If the provided paths list is empty, the local directory will be listed.

The provided paths may be relative to the local directory or absolute - this will influence the format of the returned paths in the output.

If some provided paths correlate to the arguments correlate to the same file, it will also appear multiple times in the output.

If any of the paths fails to be listed, it will result in an error in the output, but the stream will still conain all paths that were successfully listed.

Shell command: `ls`.

type Grep

type Grep struct {
	Re     *regexp.Regexp
	Invert bool
}

Grep is a modifier that filters only line that match `Re`. If Invert was set only line that did not match the regex will be returned.

Usage:

(<Stream object>).Modify(script.Grep{Re: <re>})

Shell command: `grep [-v <Invert>] <Re>`.

func (Grep) Modify

func (g Grep) Modify(line []byte) (modifed []byte, err error)

func (Grep) Name

func (g Grep) Name() string

type Modifer

type Modifer interface {
	// Modify a line. The input of this function will always be a single line from the input of the
	// stream, without the trailing '\n'. It should return the output of the stream and should
	// append a trailing '\n' if it want it to be a line in the output.
	//
	// When EOF of input stream is met, the function will be called once more with a nil line value
	// to enable output any buffered data.
	//
	// When the return modified value is nil, the line will be dicarded.
	//
	// When the returned eof value is true, the Read will return that error.
	Modify(line []byte) (modifed []byte, err error)
	// Name returns the name of the command that will represent this modifier.
	Name() string
}

Modifer modifies input lines to output. On each line of the input the Modify method is called, and the modifier can change it, omit it, or break the iteration.

type ModifierFn

type ModifierFn func(line []byte) (modifed []byte, err error)

ModifierFn is a function for modifying input lines.

func (ModifierFn) Modify

func (m ModifierFn) Modify(line []byte) (modifed []byte, err error)

func (ModifierFn) Name

func (m ModifierFn) Name() string

type PipeFn

type PipeFn func(io.Reader) Command

PipeFn is a function that returns a command given input reader for that command.

type Stream

type Stream struct {
	// contains filtered or unexported fields
}

Stream is a chain of commands: the stdout of each command in the stream feeds the following one. The stream object have different method that allow manipulating it, most of them resemble well known linux commands.

If a command which does not exist in this library is required, the `PipeTo` function should be used, which allows constructing a command object from a given input `io.Reader`.

The Stream object output can be used to be written to the stdout, to a file or to a string using the `.To*` methods. It also exposes an `io.ReadCloser` interface which allows the user using the stream output for any other usecase.

func Cat

func Cat(paths ...string) Stream

Cat outputs the contents of files.

Shell command: cat <path>.

func Echo

func Echo(s string) Stream

Echo writes to stdout.

Shell command: `echo <s>`

func Exec

func Exec(command string, args ...string) Stream

Exec executes a command and returns a stream of the stdout of the command.

func ExecHandleStderr

func ExecHandleStderr(errWriter io.Writer, cmd string, args ...string) Stream

Exec executes a command, returns a stream of the stdout of the command and enable collecting the stderr of the command.

If the errWriter is nil, it will be ignored.

For example, collecting the stderr to memory can be done by providing a `&bytes.Buffer` as `errWriter`. Writing it to stderr can be done by providing `os.Stderr` as `errWriter`. Logging it to a file can be done by providing an `os.File` as the `errWriter`.

func FromReader added in v1.0.1

func FromReader(r io.Reader) Stream

FromReader returns a new stream from a reader.

func Stdin

func Stdin() Stream

Stdin starts a stream from stdin.

func (Stream) AppendFile added in v1.0.1

func (s Stream) AppendFile(path string) error

AppendFile appends the output of the stream to a file.

func (Stream) Close

func (s Stream) Close() error

Close closes all the commands in the current stream and return the errors that occured in all of the commands by invoking the Error() function on each one of them.

func (Stream) Cut

func (s Stream) Cut(fields ...int) Stream

Cut takes selected fields from each line. The fields are 1 based (first field is 1).

Shell command: `cut -f<Fields>`.

func (Stream) Discard

func (s Stream) Discard() error

Discard executes the stream pipeline but discards the output.

func (Stream) Exec

func (s Stream) Exec(cmd string, args ...string) Stream

Exec executes a command and returns a stream of the stdout of the command.

func (Stream) ExecHandleStderr

func (s Stream) ExecHandleStderr(errWriter io.Writer, cmd string, args ...string) Stream

Exec executes a command, returns a stream of the stdout of the command and enable collecting the stderr of the command.

If the errWriter is nil, it will be ignored.

func (Stream) Grep

func (s Stream) Grep(re *regexp.Regexp) Stream

Grep filters only line that match the given regexp.

Shell command: `grep <re>`.

func (Stream) Head

func (s Stream) Head(n int) Stream

Head reads only the n first lines of the given reader. If n is a negative number, the last (-n) lines will be returned.

Shell command: `head -n <n>` / `tail -n <-n>`.

func (Stream) Modify

func (s Stream) Modify(modifier Modifer) Stream

Modify applies modifier on every line of the input.

func (Stream) PipeTo

func (s Stream) PipeTo(pipeFn PipeFn) Stream

PipeTo pipes the current stream to a new command and return the new stream. This function should be used to add custom commands that are not available in this library.

func (Stream) Read

func (s Stream) Read(b []byte) (int, error)

Read implements the io.Reader interface.

func (Stream) Sort

func (s Stream) Sort(reverse bool) Stream

Sort returns a stream with lines ordered alphabetically.

Shell command: `wc`.

func (Stream) ToFile

func (s Stream) ToFile(path string) error

ToFile dumps the output of the stream to a file.

func (Stream) ToStdout

func (c Stream) ToStdout() error

ToStdout pipes the stdout of the stream to screen.

func (Stream) ToString

func (s Stream) ToString() (string, error)

ToString reads stdout of the stream and returns it as a string.

func (Stream) ToTempFile added in v1.0.1

func (s Stream) ToTempFile() (path string, err error)

ToTempFile dumps the output of the stream to a temporary file and returns the temporary files' path.

func (Stream) Uniq

func (s Stream) Uniq() Stream

Uniq report or omit repeated lines.

Shell command: `uniq`.

func (Stream) Wc

func (s Stream) Wc() Count

Wc counts the number of lines, words and characters.

Shell command: `wc`.

type Uniq

type Uniq struct {
	WriteCount bool
	// contains filtered or unexported fields
}

Uniq report or omit repeated lines.

Shell command: `uniq`.

func (*Uniq) Modify

func (u *Uniq) Modify(line []byte) ([]byte, error)

func (*Uniq) Name

func (u *Uniq) Name() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL