complete icon indicating copy to clipboard operation
complete copied to clipboard

Why can't I run exec.Command("app do something") call inside custom predictor?

Open vlad2095 opened this issue 3 years ago • 4 comments

I would like to predict not hardcoded options but pull them from daemon every time. For example I input command app user remove, click TAB, and cli would offer me list of users which pulled by calling exec.Command("cli-get-users')

type ppred struct{}

func (y ppred) Predict(prefix string) []string {
	dateCmd := exec.Command("app", "user", "list")
	dateOut, err := dateCmd.Output()
	if err != nil {
		// handle error
	}
	s := strings.Split(strings.TrimSpace(string(dateOut)), "\n")
	return predict.Set(s).Predict(prefix)
}

Output is always empty, but when I run this code inside unit test, output is present and we're all good. If this is expected behaviour please someone explain or point me to explanation why it's not working.

vlad2095 avatar Nov 22 '21 14:11 vlad2095

It seems that you forgot datacmd.Run()? Can you see that you first get the desired output in a main() program?

posener avatar Nov 22 '21 18:11 posener

Hi, thank you for reply. cmd.Output() method under the hood runs Run() and Wait(). Anyway, I got logic I wanted other way, by making call to server without creating subprocess.

But this issue I mentioned is not solved. I suppose it's somehow can't run subprocess on my Mac or whatever because it's not even making request (although no error output either). You can try this by running even exec.Command("ls") and check out output. You'll get none..

vlad2095 avatar Nov 22 '21 18:11 vlad2095

Hi, thank you for reply. cmd.Output() method under the hood runs Run() and Wait().

Oh, right, sorry I missed it.

Anyway, I got logic I wanted other way, by making call to server without creating subprocess.

This is usually the better approach in any case :+1:

I see that you don't check the error returned from the cmd.Output() call, maybe the returned error would be informative and revile the issue?

posener avatar Nov 27 '21 10:11 posener

In any case, I tried to reproduce it on my linux machine and didn't found an issue:

The program:

// A program that complete itself
package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"strings"

	"github.com/posener/complete"
)

func main() {
	var name string
	flag.StringVar(&name, "name", "", "Give your name")
	cmp := complete.New(
		"exec1",
		complete.Command{Flags: complete.Flags{"-name": ppred{}}},
	)
	cmp.CLI.InstallName = "complete"
	cmp.CLI.UninstallName = "uncomplete"
	cmp.AddFlags(nil)
	flag.Parse()
	if cmp.Complete() {
		return
	}

	// if the completion did not do anything, we can run our program logic here.
	if name == "" {
		fmt.Println("Your name is missing")
		os.Exit(1)
	}

	fmt.Println("Hi,", name)
}

type ppred struct{}

func (y ppred) Predict(prefix complete.Args) []string {
	dateOut, err := exec.Command("ls").Output()
	if err != nil {
		log.Fatalf("Unable to run command ls: %v", err)
	}
	return strings.Split(strings.TrimSpace(string(dateOut)), "\n")
}

In the terminal:

$ cd example/exec1
$ go install ./
$ exec1 -h
Usage of exec1:
  -complete
    	Install completion for exec1 command
  -name string
    	Give your name
  -uncomplete
    	Uninstall completion for exec1 command
  -y	Don't prompt user for typing 'yes' when installing completion
$ exec1 -complete
Install completion for exec1? y
Installing...
Done!
$ source ~/.bashrc

Then I exec1 -name <tab> and I get completion for main.go, which is the file in the directory I am at. So this is the expected behavior...

Can you please check on your machine if you get the same behavior?

posener avatar Nov 27 '21 10:11 posener