github.com/linchen2chris/hugo@v0.0.0-20230307053224-cec209389705/markup/internal/external.go (about)

     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  }