external.go (1862B)
1 package internal 2 3 import ( 4 "bytes" 5 "fmt" 6 "strings" 7 8 "github.com/gohugoio/hugo/common/collections" 9 "github.com/gohugoio/hugo/common/hexec" 10 "github.com/gohugoio/hugo/markup/converter" 11 ) 12 13 func ExternallyRenderContent( 14 cfg converter.ProviderConfig, 15 ctx converter.DocumentContext, 16 content []byte, binaryName string, args []string) ([]byte, error) { 17 logger := cfg.Logger 18 19 if strings.Contains(binaryName, "/") { 20 panic(fmt.Sprintf("should be no slash in %q", binaryName)) 21 } 22 23 argsv := collections.StringSliceToInterfaceSlice(args) 24 25 var out, cmderr bytes.Buffer 26 argsv = append(argsv, hexec.WithStdout(&out)) 27 argsv = append(argsv, hexec.WithStderr(&cmderr)) 28 argsv = append(argsv, hexec.WithStdin(bytes.NewReader(content))) 29 30 cmd, err := cfg.Exec.New(binaryName, argsv...) 31 if err != nil { 32 return nil, err 33 } 34 35 err = cmd.Run() 36 37 // Most external helpers exit w/ non-zero exit code only if severe, i.e. 38 // halting errors occurred. -> log stderr output regardless of state of err 39 for _, item := range strings.Split(cmderr.String(), "\n") { 40 item := strings.TrimSpace(item) 41 if item != "" { 42 if err == nil { 43 logger.Warnf("%s: %s", ctx.DocumentName, item) 44 } else { 45 logger.Errorf("%s: %s", ctx.DocumentName, item) 46 } 47 } 48 } 49 50 if err != nil { 51 logger.Errorf("%s rendering %s: %v", binaryName, ctx.DocumentName, err) 52 } 53 54 return normalizeExternalHelperLineFeeds(out.Bytes()), nil 55 } 56 57 // Strips carriage returns from third-party / external processes (useful for Windows) 58 func normalizeExternalHelperLineFeeds(content []byte) []byte { 59 return bytes.Replace(content, []byte("\r"), []byte(""), -1) 60 } 61 62 var pythonBinaryCandidates = []string{"python", "python.exe"} 63 64 func GetPythonBinaryAndExecPath() (string, string) { 65 for _, p := range pythonBinaryCandidates { 66 if pth := hexec.LookPath(p); pth != "" { 67 return p, pth 68 } 69 } 70 return "", "" 71 }