(name, protocol string)
| 424 | var testOnlyPluginPath string |
| 425 | |
| 426 | func openClientConnection(name, protocol string) (*clientConnection, error) { |
| 427 | path := "age-plugin-" + name |
| 428 | if testOnlyPluginPath != "" { |
| 429 | path = filepath.Join(testOnlyPluginPath, path) |
| 430 | } else if strings.ContainsRune(name, os.PathSeparator) { |
| 431 | return nil, fmt.Errorf("invalid plugin name: %q", name) |
| 432 | } |
| 433 | cmd := exec.Command(path, "--age-plugin="+protocol) |
| 434 | |
| 435 | stdout, err := cmd.StdoutPipe() |
| 436 | if err != nil { |
| 437 | return nil, err |
| 438 | } |
| 439 | stdin, err := cmd.StdinPipe() |
| 440 | if err != nil { |
| 441 | return nil, err |
| 442 | } |
| 443 | |
| 444 | cc := &clientConnection{ |
| 445 | cmd: cmd, |
| 446 | Reader: stdout, |
| 447 | Writer: stdin, |
| 448 | close: func() { |
| 449 | stdin.Close() |
| 450 | stdout.Close() |
| 451 | }, |
| 452 | } |
| 453 | |
| 454 | if os.Getenv("AGEDEBUG") == "plugin" { |
| 455 | cc.Reader = io.TeeReader(cc.Reader, os.Stderr) |
| 456 | cc.Writer = io.MultiWriter(cc.Writer, os.Stderr) |
| 457 | cmd.Stderr = os.Stderr |
| 458 | } |
| 459 | |
| 460 | // We don't want the plugins to rely on the working directory for anything |
| 461 | // as different clients might treat it differently, so we set it to an empty |
| 462 | // temporary directory. |
| 463 | cmd.Dir = os.TempDir() |
| 464 | |
| 465 | if err := cmd.Start(); err != nil { |
| 466 | if errors.Is(err, exec.ErrNotFound) { |
| 467 | return nil, &NotFoundError{Name: name, Err: err} |
| 468 | } |
| 469 | return nil, err |
| 470 | } |
| 471 | |
| 472 | return cc, nil |
| 473 | } |
| 474 | |
| 475 | func (cc *clientConnection) Close() error { |
| 476 | // Close stdin and stdout and send SIGINT (if supported) to the plugin, |
no test coverage detected
searching dependent graphs…