// Exec actually performs the head func (head *SomeHead) Invoke(invocation *someutils.Invocation) (error, int) { invocation.ErrPipe.Drain() invocation.AutoHandleSignals() //TODO do something here! if len(head.Filenames) > 0 { for _, fileName := range head.Filenames { file, err := os.Open(fileName) if err != nil { return err, 1 } //err = headFile(file, head, invocation.MainPipe.Out) err = head.head(invocation.MainPipe.Out, file) if err != nil { file.Close() return err, 1 } err = file.Close() if err != nil { return err, 1 } } } else { //stdin .. err := head.head(invocation.MainPipe.Out, invocation.MainPipe.In) if err != nil { return err, 1 } } return nil, 0 }
// Exec actually performs the tee func (tee *SomeTee) Invoke(invocation *someutils.Invocation) (error, int) { invocation.ErrPipe.Drain() invocation.AutoHandleSignals() flag := os.O_CREATE if tee.isAppend { flag = flag | os.O_APPEND } writeables := uggo.ToWriteableOpeners(tee.args, flag, 0666) files, err := uggo.OpenAll(writeables) if err != nil { return err, 1 } writers := []io.Writer{invocation.MainPipe.Out} for _, file := range files { writers = append(writers, file) } multiwriter := io.MultiWriter(writers...) _, err = io.Copy(multiwriter, invocation.MainPipe.In) if err != nil { return err, 1 } for _, file := range files { err = file.Close() if err != nil { return err, 1 } } return nil, 0 }
// Exec actually performs the dirname func (dirname *SomeDirname) Invoke(invocation *someutils.Invocation) (error, int) { invocation.ErrPipe.Drain() invocation.AutoHandleSignals() for _, f := range dirname.Filenames { dir := path.Dir(f) fmt.Fprintln(invocation.MainPipe.Out, dir) } return nil, 0 }
// Exec actually performs the pwd func (pwd *SomePwd) Invoke(invocation *someutils.Invocation) (error, int) { invocation.ErrPipe.Drain() invocation.AutoHandleSignals() wd, err := os.Getwd() if err != nil { return err, 1 } fmt.Fprintln(invocation.MainPipe.Out, wd) return nil, 0 }
// Exec actually performs the zip func (z *SomeZip) Invoke(invocation *someutils.Invocation) (error, int) { invocation.ErrPipe.Drain() invocation.AutoHandleSignals() err := ZipItems(z.zipFilename, z.items) if err != nil { return err, 1 } return nil, 0 }
// Exec actually performs the touch func (touch *SomeTouch) Invoke(invocation *someutils.Invocation) (error, int) { invocation.ErrPipe.Drain() invocation.AutoHandleSignals() for _, filename := range touch.args { err := touchFile(filename) if err != nil { return err, 1 } } return nil, 0 }
func (cat *SomeCat) Invoke(invocation *someutils.Invocation) (error, int) { invocation.ErrPipe.Drain() invocation.AutoHandleSignals() if len(cat.FileNames) > 0 { for _, fileName := range cat.FileNames { file, err := os.Open(fileName) if err != nil { return err, 1 } else { if cat.isStraightCopy() { _, err = io.Copy(invocation.MainPipe.Out, file) if err != nil { return err, 1 } } else { scanner := bufio.NewScanner(file) line := 1 var prefix string var suffix string for scanner.Scan() { text := scanner.Text() if !cat.IsSqueezeBlank || len(strings.TrimSpace(text)) > 0 { if cat.IsNumber { prefix = fmt.Sprintf("%d ", line) } else { prefix = "" } if cat.IsShowEnds { suffix = "$" } else { suffix = "" } fmt.Fprintf(invocation.MainPipe.Out, "%s%s%s\n", prefix, text, suffix) } line++ } err := scanner.Err() if err != nil { return err, 1 } } file.Close() } } } else { _, err := io.Copy(invocation.MainPipe.Out, invocation.MainPipe.In) if err != nil { return err, 1 } } return nil, 0 }
// Exec actually performs the which func (which *SomeWhich) Invoke(invocation *someutils.Invocation) (error, int) { invocation.ErrPipe.Drain() invocation.AutoHandleSignals() path := os.Getenv("PATH") if runtime.GOOS == "windows" { path = ".;" + path } pl := filepath.SplitList(path) for _, arg := range which.args { checkPathParts(arg, pl, which, invocation.MainPipe.Out) } return nil, 0 }
// Invoke actually carries out the command func (tr *SomeTr) Invoke(invocation *someutils.Invocation) (error, int) { invocation.ErrPipe.Drain() invocation.AutoHandleSignals() tr.Preprocess() fu := func(inPipe io.Reader, outPipe2 io.Writer, errPipe io.Writer, line []byte) error { //println("tr processing line") //outline := line var buffer bytes.Buffer remainder := string(line) for len(remainder) > 0 { trimLeft := 1 nextPart := remainder[:trimLeft] for reg, v := range tr.translations { //fmt.Printf("Translation '%v'=>'%s' on '%s'\n", reg, v, remainder) match := reg.MatchString(remainder) if match { toReplace := reg.FindString(remainder) replacement := reg.ReplaceAllString(toReplace, v) //fmt.Printf("Replace %s=>%s\n", toReplace, replacement) nextPart = replacement //if squeezing has taken place, remove more leading chars accordingly trimLeft = len(toReplace) if !tr.IsComplement { break } } else if tr.IsComplement { // this is a double-negative - non-match of negative-regex. // This implies that set1 matches the current input character. // So, keep it as-is and break out of the loop. trimLeft = 1 nextPart = remainder[:trimLeft] break } } remainder = remainder[trimLeft:] buffer.WriteString(nextPart) } out := buffer.String() _, err := fmt.Fprintln(outPipe2, out) return err } err := someutils.LineProcessor(invocation.MainPipe.In, invocation.MainPipe.Out, invocation.ErrPipe.Out, fu) if err != nil { return err, 1 } return nil, 0 }
// Exec actually performs the unzip func (unzip *SomeUnzip) Invoke(invocation *someutils.Invocation) (error, int) { invocation.ErrPipe.Drain() invocation.AutoHandleSignals() if unzip.isTest { err := TestItems(unzip.zipname, unzip.files, invocation.MainPipe.Out, invocation.ErrPipe.Out) if err != nil { return err, 1 } } else { err := UnzipItems(unzip.zipname, unzip.destDir, unzip.files, invocation.ErrPipe.Out) if err != nil { return err, 1 } } return nil, 0 }
// Exec actually performs the xargs func (xargs *SomeXargs) Invoke(invocation *someutils.Invocation) (error, int) { invocation.ErrPipe.Drain() invocation.AutoHandleSignals() util := xargs.utilFactory() args := xargs.newArgset(util.Name()) reader := bufio.NewReader(invocation.MainPipe.In) cont := true count := 0 maxCount := 5 for cont { if count >= maxCount { count = 0 //fmt.Fprintf(errPipe, "args for '%s': %v\n", util.Name(), args) err, code := util.ParseFlags(args, invocation.ErrPipe.Out) if err != nil { return err, code } err, code = util.Invoke(invocation) if err != nil { return err, code } } line, _, err := reader.ReadLine() if err == io.EOF { cont = false } else if err != nil { return err, 1 } else { args = append(args, string(line)) if err != nil { return err, 1 } count++ } } //still more args to process if count > 0 { //fmt.Fprintf(errPipe, "args for '%s': %v\n", util.Name(), args) err, code := util.ParseFlags(args, invocation.ErrPipe.Out) if err != nil { return err, code } err, code = util.Invoke(invocation) return err, code } return nil, 0 }
// Exec actually performs the gunzip func (gunzip *SomeGunzip) Invoke(invocation *someutils.Invocation) (error, int) { invocation.ErrPipe.Drain() invocation.AutoHandleSignals() if gunzip.IsTest { err := TestGzipItems(gunzip.Filenames) if err != nil { return err, 1 } } else { err := gunzip.gunzipItems(invocation.MainPipe.In, invocation.MainPipe.Out, invocation.ErrPipe.Out) if err != nil { return err, 1 } } return nil, 0 }
// Exec actually performs the cp func (cp *SomeCp) Invoke(invocation *someutils.Invocation) (error, int) { invocation.ErrPipe.Drain() invocation.AutoHandleSignals() for _, srcGlob := range cp.SrcGlobs { srces, err := filepath.Glob(srcGlob) if err != nil { return err, 1 } for _, src := range srces { err = copyFile(src, cp.Dest, cp) if err != nil { return err, 1 } } } return nil, 0 }
// Exec actually performs the rm func (rm *SomeRm) Invoke(invocation *someutils.Invocation) (error, int) { invocation.ErrPipe.Drain() invocation.AutoHandleSignals() for _, fileGlob := range rm.fileGlobs { files, err := filepath.Glob(fileGlob) if err != nil { return err, 1 } for _, file := range files { err := delete(file, rm.IsRecursive) if err != nil { return err, 1 } } } return nil, 0 }
// Exec actually performs the basename func (basename *SomeBasename) Invoke(invocation *someutils.Invocation) (error, int) { invocation.ErrPipe.Drain() invocation.AutoHandleSignals() if basename.RelativeTo != "" { last := strings.LastIndex(basename.RelativeTo, basename.InputPath) base := basename.InputPath[:last] _, err := fmt.Fprintln(invocation.MainPipe.Out, base) if err != nil { return err, 1 } } else { _, err := fmt.Fprintln(invocation.MainPipe.Out, path.Base(basename.InputPath)) if err != nil { return err, 1 } } return nil, 0 }
// Exec actually performs the sleep func (sleep *SomeSleep) Invoke(invocation *someutils.Invocation) (error, int) { invocation.ErrPipe.Drain() invocation.AutoHandleSignals() var unitDur time.Duration switch sleep.unit { case "d": unitDur = time.Hour * 24 case "s": unitDur = time.Second case "m": unitDur = time.Minute case "h": unitDur = time.Hour default: return errors.New("Invalid time interval " + sleep.unit), 1 } time.Sleep(time.Duration(sleep.amount) * unitDur) return nil, 0 }
// Exec actually performs the tar func (t *SomeTar) Invoke(invocation *someutils.Invocation) (error, int) { invocation.ErrPipe.Drain() invocation.AutoHandleSignals() //overrideable?? destDir := "." if t.IsCreate { //OK //fmt.Printf("Create %s\n", t.ArchiveFilename) err := TarItems(t.ArchiveFilename, t.args, t, invocation.MainPipe.Out) if err != nil { return err, 1 } } else if t.IsAppend { //hmm is this OK with STDIN?? if t.ArchiveFilename == "" { return errors.New("Filename (-f) must be provided in Append mode"), 1 } //OK //fmt.Printf("Append %s\n", t.ArchiveFilename) err := TarItems(t.ArchiveFilename, t.args, t, invocation.MainPipe.Out) if err != nil { return err, 1 } } else if t.IsList { //fmt.Println("List", t.ArchiveFilename) err := TestTarItems(t.ArchiveFilename, t.args, invocation.MainPipe.In, invocation.MainPipe.Out) if err != nil { return err, 1 } } else if t.IsExtract { //fmt.Println("Extract", t.ArchiveFilename) err := UntarItems(t.ArchiveFilename, destDir, t.args, t, invocation.MainPipe.In, invocation.MainPipe.Out) if err != nil { return err, 1 } } else { return errors.New("You must use ONLY one of -c, -t or -x (create, list or extract), plus -f"), 1 } return nil, 0 }
// Exec actually performs the exec func (exe *SomeExec) Invoke(invocation *someutils.Invocation) (error, int) { invocation.ErrPipe.Drain() invocation.AutoHandleSignals() cmd := exec.Command(exe.args[0], exe.args[1:]...) cmd.Stdin = invocation.MainPipe.In cmd.Stdout = invocation.MainPipe.Out cmd.Stderr = invocation.ErrPipe.Out err := cmd.Start() if err != nil { return err, 1 } err = cmd.Wait() exitSuccess := cmd.ProcessState.Success() var exitCode int if exitSuccess { exitCode = 0 } else { // There should be a way to get the proper status on Unix. exitCode = 1 } return err, exitCode }
// Exec actually performs the mv func (mv *SomeMv) Invoke(invocation *someutils.Invocation) (error, int) { invocation.ErrPipe.Drain() invocation.AutoHandleSignals() for _, srcGlob := range mv.srcGlobs { srces, err := filepath.Glob(srcGlob) if err != nil { return err, 1 } if len(srces) < 1 { return errors.New(fmt.Sprintf("Source glob '%s' does not match any files\n", srcGlob)), 1 } for _, src := range srces { err = moveFile(src, mv.dest) if err != nil { fmt.Fprintf(invocation.ErrPipe.Out, "Error %v\n", err) return err, 1 } } } return nil, 0 }
// Exec actually performs the grep func (grep *SomeGrep) Invoke(invocation *someutils.Invocation) (error, int) { invocation.ErrPipe.Drain() invocation.AutoHandleSignals() reg, err := compile(grep.pattern, grep) if err != nil { return err, 1 } if len(grep.globs) > 0 { files := []string{} for _, glob := range grep.globs { results, err := filepath.Glob(glob) if err != nil { return err, 1 } if len(results) < 1 { //no match return errors.New("grep: cannot access " + glob + ": No such file or directory"), 1 } files = append(files, results...) } err = grepAll(reg, files, grep, invocation.MainPipe.Out) if err != nil { return err, 1 } } else { if uggo.IsPipingStdin() { //check STDIN err = grepReader(invocation.MainPipe.In, "", reg, grep, invocation.MainPipe.Out) if err != nil { return err, 1 } } else { //NOT piping. return errors.New("Not enough args"), 1 } } return nil, 0 }
// Exec actually performs the ls func (ls *SomeLs) Invoke(invocation *someutils.Invocation) (error, int) { invocation.ErrPipe.Drain() invocation.AutoHandleSignals() out := tabwriter.NewWriter(invocation.MainPipe.Out, 4, 4, 1, ' ', 0) args, err := getDirList(ls.globs, ls, invocation.MainPipe.In, invocation.MainPipe.Out, invocation.ErrPipe.Out) if err != nil { return err, 1 } counter := 0 lastWasDir := false for i, arg := range args { if !strings.HasPrefix(arg, ".") || ls.AllFiles || strings.HasPrefix(arg, "..") || "." == arg { argInfo, err := os.Stat(arg) if err != nil { fmt.Fprintln(invocation.ErrPipe.Out, "stat failed for ", arg) return err, 1 } if argInfo.IsDir() { if len(args) > 1 { //if more than one, print dir name before contents if i > 0 { fmt.Fprintf(out, "\n") } if !lastWasDir { fmt.Fprintf(out, "\n") } fmt.Fprintf(out, "%s:\n", arg) } dir := arg //show . and .. if ls.AllFiles { df, err := os.Stat(filepath.Dir(dir)) if err != nil { fmt.Fprintf(out, "Error opening parent dir: %v", err) } else { printEntry("..", df, out, ls, &counter) } df, err = os.Stat(dir) if err != nil { fmt.Fprintf(out, "Error opening dir: %v", err) } else { printEntry(".", df, out, ls, &counter) } } err := list(out, invocation.ErrPipe.Out, dir, "", ls, &counter) if err != nil { return err, 1 } if len(args) > 1 { fmt.Fprintf(out, "\n") } } else { listItem(argInfo, out, invocation.ErrPipe.Out, filepath.Dir(arg), "", ls, &counter) } lastWasDir = argInfo.IsDir() } } out.Flush() return nil, 0 }
// Exec actually performs the tail func (tail *SomeTail) Invoke(invocation *someutils.Invocation) (error, int) { invocation.ErrPipe.Drain() invocation.AutoHandleSignals() if len(tail.Filenames) > 0 { for _, fileName := range tail.Filenames { finf, err := os.Stat(fileName) if err != nil { return err, 1 } file, err := os.Open(fileName) if err != nil { return err, 1 } seek := int64(0) if finf.Size() > 10000 { //just get last 10K (good enough for now) seek = finf.Size() - 10000 _, err = file.Seek(seek, 0) if err != nil { return err, 1 } } end, err := tailReader(file, seek, tail, invocation.MainPipe.Out) if err != nil { file.Close() return err, 1 } err = file.Close() if err != nil { return err, 1 } if tail.FollowByName { sleepIntervalMs := time.Duration(tail.SleepInterval * 1000) for { //sleep n.x seconds //use milliseconds to get some accuracy with the int64 time.Sleep(sleepIntervalMs * time.Millisecond) finf, err := os.Stat(fileName) if err != nil { return err, 1 } file, err := os.Open(fileName) if err != nil { return err, 1 } _, err = file.Seek(end, 0) if err != nil { return err, 1 } if finf.Size() > end { end, err = tailReader(file, end, tail, invocation.MainPipe.Out) if err != nil { file.Close() return err, 1 } } else { //TODO start again } err = file.Close() if err != nil { return err, 1 } } } } } else { //stdin .. _, err := tailReader(invocation.MainPipe.In, 0, tail, invocation.MainPipe.Out) if err != nil { return err, 1 } } return nil, 0 }
// Exec actually performs the wc func (wc *SomeWc) Invoke(invocation *someutils.Invocation) (error, int) { invocation.ErrPipe.Drain() invocation.AutoHandleSignals() if len(wc.args) > 0 { //treat no args as all args if !wc.IsWords && !wc.IsLines && !wc.IsBytes { wc.IsWords = true wc.IsLines = true wc.IsBytes = true } for _, fileName := range wc.args { bytes := int64(0) words := int64(0) lines := int64(0) //get byte count file, err := os.Open(fileName) if err != nil { return err, 1 } err = countWords(file, wc, &bytes, &words, &lines) if err != nil { file.Close() return err, 1 } err = file.Close() if err != nil { return err, 1 } if wc.IsWords && !wc.IsLines && !wc.IsBytes { fmt.Fprintf(invocation.MainPipe.Out, "%d %s\n", words, fileName) } else if !wc.IsWords && wc.IsLines && !wc.IsBytes { fmt.Fprintf(invocation.MainPipe.Out, "%d %s\n", lines, fileName) } else if !wc.IsWords && !wc.IsLines && wc.IsBytes { fmt.Fprintf(invocation.MainPipe.Out, "%d %s\n", bytes, fileName) } else { fmt.Fprintf(invocation.MainPipe.Out, "%d %d %d %s\n", lines, words, bytes, fileName) } } } else { //stdin .. if !wc.IsWords && !wc.IsLines && !wc.IsBytes { wc.IsWords = true } bytes := int64(0) words := int64(0) lines := int64(0) err := countWords(invocation.MainPipe.In, wc, &bytes, &words, &lines) if err != nil { return err, 1 } if wc.IsWords && !wc.IsLines && !wc.IsBytes { fmt.Fprintf(invocation.MainPipe.Out, "%d\n", words) } else if !wc.IsWords && wc.IsLines && !wc.IsBytes { fmt.Fprintf(invocation.MainPipe.Out, "%d\n", lines) } else if !wc.IsWords && !wc.IsLines && wc.IsBytes { fmt.Fprintf(invocation.MainPipe.Out, "%d\n", bytes) } else { fmt.Fprintf(invocation.MainPipe.Out, "%d %d %d\n", lines, words, bytes) } } return nil, 0 }
// Exec actually performs the gzip func (gz *SomeGzip) Invoke(invocation *someutils.Invocation) (error, int) { //fmt.Printf("invocation: %+v\n", invocation) //fmt.Printf("gz: %+v\n", gz) invocation.ErrPipe.Drain() invocation.AutoHandleSignals() if len(gz.Filenames) < 1 { //pipe in? var writer io.Writer var outputFilename string if gz.outFile != "" { outputFilename = gz.outFile var err error writer, err = os.Create(outputFilename) if err != nil { return err, 1 } } else { // fmt.Printf("stdin to stdout: %+v\n", gz) outputFilename = "S" //seems to be the default used by gzip writer = invocation.MainPipe.Out } err := gz.doGzip(invocation.MainPipe.In, writer, filepath.Base(outputFilename)) if err != nil { return err, 1 } } else { //todo make sure it closes saved file cleanly for _, inputFilename := range gz.Filenames { inputFile, err := os.Open(inputFilename) if err != nil { return err, 1 } defer inputFile.Close() var writer io.Writer if !gz.IsStdout { outputFilename := inputFilename + ".gz" gzf, err := os.Create(outputFilename) if err != nil { return err, 1 } defer gzf.Close() writer = gzf } else { writer = invocation.MainPipe.Out } err = gz.doGzip(inputFile, writer, filepath.Base(inputFilename)) if err != nil { return err, 1 } err = inputFile.Close() if err != nil { return err, 1 } // only remove source if specified and possible if !gz.IsKeep && !gz.IsStdout { err = os.Remove(inputFilename) if err != nil { return err, 1 } } } } return nil, 0 }