someutils

package module
v0.0.0-...-b27df3f Latest Latest
Warning

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

Go to latest
Published: Apr 19, 2014 License: BSD-3-Clause Imports: 11 Imported by: 1

README

someutils

Some CLI utilities written in Go.

  • Mainly intended as Unix-like commands for Windows, but cross-platform anyway.

  • Covers similar ground to coreutils, but not intended as a replacement. (Won't ever support all commands & options).

  • Just because.

  • WARNING: someutils isn't intended for use as a library YET. The API can and will change, with the idea being to facilitate cross-platform, shell-like scripting in Go.

  • New and Experimental in v0.5: you can use someutils as a library (but the API will change)

    pipeline := someutils.NewPipeline(someutils.Wrap(wget.WgetToOut()), Head(2), Tr("h", "G")) invocation, out, errout := pipeline.InvokeReader(strings.NewReader("www.golang.org\n")) lastOrErrInvocation := invocation.Wait() fmt.Println(out.String())

Installation.

  • Grab some recent (v0.3.0) Windows binaries zipped up for 32-bit Windows and 64-bit Windows.
  • Just unzip somewhere on your %PATH% (environment variable).
  • (These binaries were built and uploaded with goxc, ofcourse)
Method 2: go get all binaries into your GOPATH

NOTE: On Unix systems in particular, be careful that your system PATH elements come BEFORE GOPATH within your PATH environment variable

  1. go get github.com/laher/someutils/./...
  2. ls, pwd etc

You could also use go get to pick out a subset of those commands.

Method 3: just install the some command, (similar to busybox):
  1. go get github.com/laher/someutils/cmd/some
  2. some ls, some pwd etc
  3. Optionally, use alias or doskey to make some behave more like busybox.

Scope etc

My initial target is to get my Windows CLI a bit closer to being as productive as my Linux CLI, by creating many small utilities under one umbrella. Then, who knows. I do like the idea of a Go/Linux, as opposed to Gnu/Linux :)

Some commands are not included, because they're either ubiquitous anyway (such as echo,cd,whoami), just too big, or hard to acheive with pure Go.

I'll just keep adding stuff as I need it. Contributions welcome!

Progress

So far, limited versions of the following commands are available: You can also use 'some [cmd] [args...]' for any of these.

Command Options supported STDIN support Notes
basename TODO: -a, -z
cat -Ens Yes
cp -r n/a TODO: check symlink behaviour. Test large file support
dirname n/a
grep -nvHi -E -P Yes TODO: binary files support. !!No support for BRE - uses -E by default.
gunzip -k TODO TODO: -f, prompt when file exists
gzip -k TODO TODO: -f, prompt when file exists
head -n Yes TODO: -c
ls -lahr -1 Yes TODO: -p -t
mv n/a TODO: check symlink behaviour
pwd n/a
rm -r n/a TODO: check symlink behaviour
scp -r -P ? INCOMPLETE - see scp-go .
sleep n/a
tail -n -F Yes TODO: -c, -f (by descriptor rather than by name). Bug: won't currently print last line unless terminated by a CR.
tar -cvf -x -t -r Yes (IN+OUT) Just the core functionality so far.
tr Yes
tee -a Yes TODO: -i
touch n/a
unzip -t TODO(STDOUT) Password support would not be straightforward (not supported by standard lib)
wc -c -l -w
which -a n/a
wget -c -o n/a TODO: multi-threading? (not part of real wget). See wget-go
zip TODO Password support would not be straightforward (not supported by standard lib)
ToMaybeDo
  • stat,size,file,type
  • split,join,sort
  • shred
  • chmod/chown (relevant? Yes I think so)
  • diff (too big? Maybe a minimal version would be good here)
  • more (how easy is it?)
  • du/dh (need OS-specifics: syscall would probably cover it for Unix and Windows)
  • find/locate (find is a bit of a monster. locate is probably a stretch)
  • ln (would it need some non-Go stuff for Windows? Yes - maybe an 'exec' at this stage)
  • ps,kill,pgrep,pkill (need to explore mileage of os.FindProcess, syscall.Kill)
  • id,w (is it doable cross-platform?)
  • sshd (minimal version, for hosting file transfers etc), ssh (maybe just for running remote commands. Terminal handling might be too challenging for now)
  • traceroute (see wtn. Requires setuid & therefore chowning + chmodding on Unix - on Windows I think you'd just need to run as administrator)
  • ping (see above)
  • dig (I think. Raw DNS requests & collect responses. Hmm, investigate go.net packages)
  • chroot (chroot possible for unix via syscall - see gobox)
TooBig?
  • less
  • a text editor
  • top
  • dd (I guess. Maybe not)
  • awk, sed
  • xargs, find -exec
  • rsync (algorithms might be a bit hard)
  • cron (I guess service handling is another chapter aswell)
Not possible/easy with pure Go
  • bg,fg
  • fsck

See Also

  • I have separated out the 'flag' functionality, and some other relevant behaviour, into a separate package, uggo
  • I drew inspiration early on from a couple of similar projects - many thanks to gobox and go-coreutils. In both cases I considered a fork but my focus is just a little too different to make it feasible. Cheers guys

Documentation

Overview

Package someutils offers some CLI utilities for the commandline and also as Go objects

Attention

This package is in an alpha stage, and still in heavy development. APIs may change, and things may break.

See http://github.com/laher/someutils for details.

Introduction

Index

Examples

Constants

View Source
const EXIT_OK = 0
View Source
const (
	VERSION = "0.5.1-snapshot"
)

Variables

View Source
var (
	SIGINT = &SignalSimple{1}
)

Functions

func Call

func Call(name string, args []string) (error, int)

deprecated. Use GetCliUtil, ParseFlags & Exec instead.

func CallUtil

func CallUtil(util CliPipable, args []string, invocation *Invocation) (error, int)

func CliExists

func CliExists(name string) bool

Has a CLI function been registered?

func Exists

func Exists(name string) bool

deprecated. Use CliExists instead.

func FanoutByLineStrategy

func FanoutByLineStrategy(fanout *SomeFanout, invocation *Invocation) (chan *PipelineInvocation, chan error)

func LineProcessor

func LineProcessor(inPipe io.Reader, outPipe io.Writer, errPipe io.Writer, fu LineProcessorFunc) error

Process line-by-line

func List

func List() []string

func PipableExists

func PipableExists(name string) bool

func Register

func Register(u CliPipable)

Registers utils for use by 'some' command.

func RegisterPipable

func RegisterPipable(somefunc CliPipableFactory)

func RegisterSimple

func RegisterSimple(somefunc CliPipableSimpleFactory)

func StdInvoke

func StdInvoke(pcu CliPipable, call []string) (error, int)

convenience method for CLI handlers

Types

type ArchiveItem

type ArchiveItem struct {
	//if FileSystemPath is empty, use Data instead
	FileSystemPath string
	ArchivePath    string
	Data           []byte
}

ArchiveItem is used by tar & zip

type CliPipable

type CliPipable interface {
	NamedPipable
	Cliable
}

PipableUtil represents a util which can be initialized by flags & executed on a Pipeline

func WrapCliPipable

func WrapCliPipable(ps CliPipableSimple) CliPipable

type CliPipableFactory

type CliPipableFactory func() CliPipable

type NamedPipableFactory func() NamedPipable

func GetCliPipableFactory

func GetCliPipableFactory(name string) CliPipableFactory

type CliPipableSimple

type CliPipableSimple interface {
	NamedPipableSimple
	Cliable
}

type CliPipableSimpleFactory

type CliPipableSimpleFactory func() CliPipableSimple

type CliPipableSimpleWrapper

type CliPipableSimpleWrapper struct {
	CliPipableSimple
}

func (*CliPipableSimpleWrapper) Invoke

func (cpsw *CliPipableSimpleWrapper) Invoke(i *Invocation) (error, int)

type Cliable

type Cliable interface {
	ParseFlags(call []string, errPipe io.Writer) (error, int)
}

type FanoutStrategy

type FanoutStrategy func(*SomeFanout, *Invocation) (chan *PipelineInvocation, chan error)

type Invocation

type Invocation struct {
	Pipeline *Pipeline
	Pipable  Pipable
	MainPipe *Pipe
	ErrPipe  *Pipe
	/*
		MainPipe.In         io.Reader
		MainPipe.Out        io.Writer
		ErrPipe.In      io.Reader
		ErrPipe.Out     io.Writer
	*/
	SignalReceiver chan Signal
	ExitCode       *int
	Err            error
	Closed         bool
	// contains filtered or unexported fields
}

A set of invocation (In, Out, ErrOut, and even ErrIn (but ErrIn is usually only used by the special 'Redirector' util) Note that Pipables are not expected to use this type (Pipables should not need any dependency on someutils - just the implicit implementation of the Pipable interface)

func AwaitAllErrors

func AwaitAllErrors(e chan *Invocation, count int) (bool, []*Invocation)

Await all errors forever

func AwaitAllErrorsFor

func AwaitAllErrorsFor(e chan *Invocation, count int, timeout time.Duration) (bool, []*Invocation)

Await Errors for a duration

func InvocationFromReader

func InvocationFromReader(inPipe io.Reader) (*Invocation, *bytes.Buffer, *bytes.Buffer)

Factory taking a string for Stdin, and using byte buffers for the sdout and stderr invocation This returns the byte buffers to avoid the need to cast. (The assumption being that you'll want to call .Bytes() or .String() on those buffers)

func NewErrorState

func NewErrorState(err error) *Invocation

func NewInvocation

func NewInvocation(inPipe io.Reader, outPipe io.Writer, errPipe io.Writer) *Invocation

Factory for a pipeline with the given invocation

func StdInvocation

func StdInvocation() *Invocation

Convenience method returns the Stdin/Stdout/Stderr invocation associated with this process

func Wait

func Wait(e chan *Invocation, count int) *Invocation

Await completion, or first error

func WaitFor

func WaitFor(e chan *Invocation, count int, timeout time.Duration) *Invocation

Await completion or error, for a duration

func (*Invocation) AutoHandleSignals

func (i *Invocation) AutoHandleSignals()
func (i *Invocation) AutoPipeErrInOut() {
	go autoPipe(i.ErrPipe.Out, i.ErrPipe.In)
}

TODO!!

func (*Invocation) Close

func (i *Invocation) Close() error
func (i *Invocation) PipeToPipeline(pipeline *Pipeline) (error, chan *Invocation, int) {
	if i.Pipeline != nil {
		return errors.New("This invocation already was already invoked!"), nil, 0
	}
	i.Pipeline = pipeline
	invocationChannel, count := pipeline.Invoke(i)
	return nil, invocationChannel, count
}

warning. This closes a channel. Don't call it twice - panic ensues!

func (*Invocation) Pipe

func (i *Invocation) Pipe(pipable Pipable) (error, int)

func (*Invocation) Wait

func (i *Invocation) Wait() *int

func (*Invocation) WaitUpTo

func (i *Invocation) WaitUpTo(timeout time.Duration) (error, *int)

type LineProcessorFunc

type LineProcessorFunc func(io.Reader, io.Writer, io.Writer, []byte) error

A function which processses a line from a reader

type Named

type Named interface {
	Name() string
}

type NamedPipable

type NamedPipable interface {
	Pipable
	Named
}

a Named Pipable can be registered for use by e.g. xargs

func WrapNamed

func WrapNamed(ps NamedPipableSimple) NamedPipable

type NamedPipableSimple

type NamedPipableSimple interface {
	PipableSimple
	Named
}

type NamedPipableSimpleFactory

type NamedPipableSimpleFactory func() NamedPipableSimple

type NamedPipableSimpleWrapper

type NamedPipableSimpleWrapper struct {
	NamedPipableSimple
}

func (*NamedPipableSimpleWrapper) Invoke

func (npsw *NamedPipableSimpleWrapper) Invoke(i *Invocation) (error, int)

type Pipable

type Pipable interface {
	Invoke(i *Invocation) (error, int)
}

a Pipable can be executed on a pipeline

func Wrap

func Wrap(ps PipableSimple) Pipable

type PipableFactory

type PipableFactory func() Pipable

func GetPipableFactory

func GetPipableFactory(name string) PipableFactory

type PipableSimple

type PipableSimple interface {
	Exec(inPipe io.Reader, outPipe io.Writer, errPipe io.Writer) (error, int)
}

a PipableSimple can be executed on a pipeline when wrapped inside a PipableSimpleWrapper

type PipableSimpleFactory

type PipableSimpleFactory func() PipableSimple

type PipableSimpleWrapper

type PipableSimpleWrapper struct {
	PipableSimple
}

func (*PipableSimpleWrapper) Invoke

func (psw *PipableSimpleWrapper) Invoke(i *Invocation) (error, int)

type PipableWrapper

type PipableWrapper struct {
	PipableSimple
}

type Pipe

type Pipe struct {
	In  io.Reader
	Out io.Writer
}

func (*Pipe) CloseIfClosers

func (p *Pipe) CloseIfClosers()

func (*Pipe) Drain

func (p *Pipe) Drain()

type PipeRedirector

type PipeRedirector struct {
	Filename string
	// contains filtered or unexported fields
}

PipeRedirector represents and performs a redirection between one Execable and another Note that PipeRedirector is an Execable but not a CLI util

func ErrTo

func ErrTo(filename string) *PipeRedirector

Factory for redirecting 'err' pipe to a file

func ErrToNull

func ErrToNull() *PipeRedirector

Factory for redirecting 'err' pipe to Null (nowhere)

func ErrToOut

func ErrToOut() *PipeRedirector

Factory for redirecting 'err' pipe to 'out' pipe

func OutTo

func OutTo(filename string) *PipeRedirector

Factory for redirecting 'out' pipe to a file

func OutToErr

func OutToErr() *PipeRedirector

Factory for redirecting 'out' pipe to 'err' pipe

func OutToNull

func OutToNull() *PipeRedirector

Factory for redirecting 'out' pipe to Null (nowhere)

func (*PipeRedirector) Invoke

func (redirector *PipeRedirector) Invoke(invocation *Invocation) (error, int)

Exec actually performs the redirection

type Pipeline

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

Chains together the input/output of utils in a 'pipeline'

Example
package main

import (
	"fmt"
	"io"
	"strings"
)

type ExampleUtil struct {
}

func (ex *ExampleUtil) Exec(inPipe io.Reader, outPipe io.Writer, errPipe io.Writer) (error, int) {
	err := LineProcessor(inPipe, outPipe, errPipe, func(inPipe io.Reader, outPipe io.Writer, errPipe io.Writer, line []byte) error {
		_, err := fmt.Fprintln(outPipe, string(line))
		return err
	})
	if err != nil {
		return err, 1
	}
	return nil, 0
}

func main() {
	p := NewPipeline(&PipableSimpleWrapper{&ExampleUtil{}}, &PipableSimpleWrapper{&ExampleUtil{}})
	mainInvocation, out, err := p.InvokeReader(strings.NewReader("Hi\nHo\nhI\nhO\n")) //, os.Stdout, os.Stderr)
	//e, _ := p.Invoke(mainInvocation)
	//<-e
	//<-e
	mainInvocation.Wait()
	fmt.Println(out.String())
	fmt.Println(err.String())
}
Output:

Hi
Ho
hI
hO

func NewPipeline

func NewPipeline(pipables ...Pipable) *Pipeline

func (*Pipeline) ExecAndWait

func (p *Pipeline) ExecAndWait(invocation *PipelineInvocation) *Invocation

// Intended as a subtype for Pipable which can redirect the error output of the previous command. This is treated as a special case because commands do not typically have access to this.

type WillRedirectErrIn interface {
	SetErrIn(errMainPipe.In io.Reader)
}

Pipe and wait for errors (up until a timeout occurs)

func (*Pipeline) ExecAndWaitUpTo

func (p *Pipeline) ExecAndWaitUpTo(invocation *PipelineInvocation, timeout time.Duration) *Invocation

Pipe and wait for errors (up until a timeout occurs)

func (*Pipeline) Invoke

func (p *Pipeline) Invoke(mainInvocation *PipelineInvocation) (chan *Invocation, int)

Run pipables in a sequence, weaving together their inputs and outputs appropriately

func (*Pipeline) InvokeReader

func (p *Pipeline) InvokeReader(inPipe io.Reader) (*PipelineInvocation, *bytes.Buffer, *bytes.Buffer)

type PipelineInvocation

type PipelineInvocation struct {
	*Invocation
	Invocations []*Invocation
}

func NewPipelineInvocation

func NewPipelineInvocation(invocation *Invocation) *PipelineInvocation

func (*PipelineInvocation) Add

func (pi *PipelineInvocation) Add(invocation *Invocation)

func (*PipelineInvocation) SignalAll

func (pi *PipelineInvocation) SignalAll(signal Signal)

func (*PipelineInvocation) Wait

func (pi *PipelineInvocation) Wait() *Invocation

Wait until an exit status has occurred

func (*PipelineInvocation) WaitUpTo

func (pi *PipelineInvocation) WaitUpTo(timeout time.Duration) *Invocation

Wait until an exit status has occurred

type Signal

type Signal interface {
	Status() int
}

type SignalSimple

type SignalSimple struct {
	StatusCode int
}

func (*SignalSimple) Status

func (ss *SignalSimple) Status() int

type SomeCd

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

SomeCd represents and performs a `cd` invocation

func Cd

func Cd(destDir string) *SomeCd

Factory for *SomeCd

func NewCd

func NewCd() *SomeCd

Factory for *SomeCd

func (*SomeCd) Invoke

func (cd *SomeCd) Invoke(invocation *Invocation) (error, int)

Exec actually performs the cd

func (*SomeCd) Name

func (cd *SomeCd) Name() string

Name() returns the name of the util

func (*SomeCd) ParseFlags

func (cd *SomeCd) ParseFlags(call []string, errPipe io.Writer) error

ParseFlags parses flags from a commandline []string

type SomeFanout

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

SomeFanout represents and performs a `fanout` invocation

func FanoutByLine

func FanoutByLine(args ...Pipable) *SomeFanout

Factory for *SomeFanout

func NewFanout

func NewFanout() *SomeFanout

Factory for *SomeFanout

func (*SomeFanout) Invoke

func (fanout *SomeFanout) Invoke(invocation *Invocation) (error, int)

Invoke actually performs the fanout

func (*SomeFanout) Name

func (fanout *SomeFanout) Name() string

Name() returns the name of the util

type SomeLn

type SomeLn struct {
	IsForce    bool
	IsSymbolic bool
	// contains filtered or unexported fields
}

func (*SomeLn) Exec

func (ln *SomeLn) Exec(inPipe io.Reader, outPipe io.Writer, errPipe io.Writer) error

func (*SomeLn) ParseFlags

func (ln *SomeLn) ParseFlags(call []string, errPipe io.Writer) error
func init() {
	Register({
		"ln",
		Ln})
}

Directories

Path Synopsis
cmd
cat
cp
ls
mv
pwd
rm
scp
tar
tee
tr
wc
zip

Jump to

Keyboard shortcuts

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