Выполнить команду с помощью стандартного ввода, написанного программно и подключенного к os.stdin - PullRequest
0 голосов
/ 16 апреля 2020

Я выполняю docker -композитный исполняемый файл из моей Go программы. Чтобы настроить его, я передаю конфигурацию docker -compose напрямую на стандартный * docker -compose. В большинстве случаев это работает нормально, код выглядит примерно так (я удалил всю обработку ошибок в фрагментах кода для простоты):

args = append([]string{"-f", "-"}, args...)
cmd := exec.Command("docker-compose", args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Stdin = strings.NewReader(input)
cmd.Run()

args - это аргументы, переданные docker -compose , input - это docker -компонованная конфигурация в виде строки YAML.

Хотя это работает в большинстве случаев, происходит сбой с интерактивными командами. Stdin не подключен к os.stdin, и команды не выполняются. Я могу получить интерактивные команды для работы со следующим кодом:

cmd := exec.Command("docker-compose", args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin
cmd.Run()

Но это без добавления конфигурации, что мне нужно сделать в конце. Я пытался каким-то образом объединить эти версии, но не смог заставить это работать:

input, _ := getDockerComposeAsYaml(config)
args = append([]string{"-f", "-"}, args...)
cmd := exec.Command("docker-compose", args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr

stdin, _ := cmd.StdinPipe()

go func() {
    //defer stdin.Close()
    io.WriteString(stdin, input)
}()
cmd.Run()

Я пробовал приведенный выше код с явным закрытием stdin и без него, хотя требуемое поведение должно происходить без его закрытия, как я хочу, чтобы стандартный ввод был открыт для интерактивного использования. Без закрытия программа просто зависает навсегда, с закрытием stdin она не работает в интерактивном режиме, как ожидалось.

Как правильно подключить stdin исполняемой программы к os.stdin, оставаясь при этом способным передать некоторые данные в начале?

1 Ответ

0 голосов
/ 16 апреля 2020

Программа, которая записывает в stdin (канал, созданный с помощью cmd.StdinPipe), должна:

  1. записать строку input
  2. Затем l oop на действительное os.Stdin, запись всего, что попадает в stdin
  3. Когда EOF встречается на os.Stdin, закройте stdin явно.

Однако подпроцесс может завершиться до того, как os.Stdin закрыто. В этом случае труба (stdin будет закрыта на exec.Command). Ваш l oop должен проверить закрытый stdin и выйти из программы, если это произойдет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...