hugo/markup/internal/external.go
2024-01-28 23:14:09 +01:00

73 lines
1.8 KiB
Go

package internal
import (
"bytes"
"fmt"
"strings"
"github.com/gohugoio/hugo/common/collections"
"github.com/gohugoio/hugo/common/hexec"
"github.com/gohugoio/hugo/markup/converter"
)
func ExternallyRenderContent(
cfg converter.ProviderConfig,
ctx converter.DocumentContext,
content []byte, binaryName string, args []string,
) ([]byte, error) {
logger := cfg.Logger
if strings.Contains(binaryName, "/") {
panic(fmt.Sprintf("should be no slash in %q", binaryName))
}
argsv := collections.StringSliceToInterfaceSlice(args)
var out, cmderr bytes.Buffer
argsv = append(argsv, hexec.WithStdout(&out))
argsv = append(argsv, hexec.WithStderr(&cmderr))
argsv = append(argsv, hexec.WithStdin(bytes.NewReader(content)))
cmd, err := cfg.Exec.New(binaryName, argsv...)
if err != nil {
return nil, err
}
err = cmd.Run()
// Most external helpers exit w/ non-zero exit code only if severe, i.e.
// halting errors occurred. -> log stderr output regardless of state of err
for _, item := range strings.Split(cmderr.String(), "\n") {
item := strings.TrimSpace(item)
if item != "" {
if err == nil {
logger.Warnf("%s: %s", ctx.DocumentName, item)
} else {
logger.Errorf("%s: %s", ctx.DocumentName, item)
}
}
}
if err != nil {
logger.Errorf("%s rendering %s: %v", binaryName, ctx.DocumentName, err)
}
return normalizeExternalHelperLineFeeds(out.Bytes()), nil
}
// Strips carriage returns from third-party / external processes (useful for Windows)
func normalizeExternalHelperLineFeeds(content []byte) []byte {
return bytes.Replace(content, []byte("\r"), []byte(""), -1)
}
var pythonBinaryCandidates = []string{"python", "python.exe"}
func GetPythonBinaryAndExecPath() (string, string) {
for _, p := range pythonBinaryCandidates {
if pth := hexec.LookPath(p); pth != "" {
return p, pth
}
}
return "", ""
}