Repository: go-acme/lego (language: go)

Issue:
'--dns exec' show output in real time?
### Welcome

- [X] Yes, I've searched similar issues on GitHub and didn't find any.

### How do you use lego?

Binary

### Detailed Description

I'm working on a shell script to use with `--dns exec` (to manually add/remove DNS records), and running into issues that take significantly longer than they should to debug, because the part of `lego` which runs my script appears to be gathering the script's output in memory and then dumping it to the output stream all at once. The process of adding/removing DNS records can take up to two minutes per name, so if I'm testing with a certificate having multiple hostnames on it (i.e. `name1.domain.xyz`, `'name2.domain.xyz`, and `name3.domain.xyz`), I see no output at all for several minutes and then get a dump all at once at the end.

I'm looking at `providers/dns/exec/exec.go`, but I don't know enough about the exec module to know if this is even possible, so ... is there a way to make the code print each line of input, as soon as the external script prints it?


Discussion / hints:
Hello,

first, what drives you to use `exec` instead of "real" DNS implementation? Is your provider not supported?



Fix patch:
diff --git a/providers/dns/exec/exec.go b/providers/dns/exec/exec.go
index a07cba0a63..23fdaf3849 100644
--- a/providers/dns/exec/exec.go
+++ b/providers/dns/exec/exec.go
@@ -2,6 +2,7 @@
 package exec
 
 import (
+	"bufio"
 	"context"
 	"errors"
 	"fmt"
@@ -117,10 +118,27 @@ func (d *DNSProvider) run(ctx context.Context, command, domain, token, keyAuth s
 
 	cmd := exec.CommandContext(ctx, d.config.Program, args...)
 
-	output, err := cmd.CombinedOutput()
-	if len(output) > 0 {
-		log.Println(string(output))
+	stdout, err := cmd.StdoutPipe()
+	if err != nil {
+		return fmt.Errorf("create pipe: %w", err)
+	}
+
+	cmd.Stderr = cmd.Stdout
+
+	err = cmd.Start()
+	if err != nil {
+		return fmt.Errorf("start command: %w", err)
 	}
 
-	return err
+	scanner := bufio.NewScanner(stdout)
+	for scanner.Scan() {
+		log.Println(scanner.Text())
+	}
+
+	err = cmd.Wait()
+	if err != nil {
+		return fmt.Errorf("wait command: %w", err)
+	}
+
+	return nil
 }


Test patch: