Skip to content

Commit

Permalink
Improve LookPath
Browse files Browse the repository at this point in the history
  • Loading branch information
bep committed Dec 19, 2020
1 parent 1415efd commit 4a8267d
Show file tree
Hide file tree
Showing 18 changed files with 128 additions and 43 deletions.
45 changes: 45 additions & 0 deletions common/hexec/safeCommand.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright 2020 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package hexec

import (
"context"

"os/exec"

"github.com/cli/safeexec"
)

// SafeCommand is a wrapper around os/exec Command which uses a LookPath
// implementation that does not search in current directory before looking in PATH.
// See https://github.com/cli/safeexec and the linked issues.
func SafeCommand(name string, arg ...string) (*exec.Cmd, error) {
bin, err := safeexec.LookPath(name)
if err != nil {
return nil, err
}

return exec.Command(bin, arg...), nil
}

// SafeCommandContext wraps CommandContext
// See SafeCommand for more context.
func SafeCommandContext(ctx context.Context, name string, arg ...string) (*exec.Cmd, error) {
bin, err := safeexec.LookPath(name)
if err != nil {
return nil, err
}

return exec.CommandContext(ctx, bin, arg...), nil
}
7 changes: 5 additions & 2 deletions create/content.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ import (

"io"
"os"
"os/exec"
"path/filepath"
"strings"

"github.com/gohugoio/hugo/common/hexec"
"github.com/gohugoio/hugo/hugofs/files"

"github.com/gohugoio/hugo/hugofs"
Expand Down Expand Up @@ -106,7 +106,10 @@ func NewContent(
jww.FEEDBACK.Printf("Editing %s with %q ...\n", targetPath, editor)

editorCmd := append(strings.Fields(editor), contentPath)
cmd := exec.Command(editorCmd[0], editorCmd[1:]...)
cmd, err := hexec.SafeCommand(editorCmd[0], editorCmd[1:]...)
if err != nil {
return err
}
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ require (
github.com/bep/gitmap v1.1.2
github.com/bep/golibsass v0.7.0
github.com/bep/tmc v0.5.1
github.com/cli/safeexec v1.0.0
github.com/disintegration/gift v1.2.1
github.com/dlclark/regexp2 v1.4.0 // indirect
github.com/dustin/go-humanize v1.0.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 h1:SKI1/fuSdodxmNNyVBR8d7X/HuLnRpvvFO0AgyQk764=
github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U=
github.com/cli/safeexec v1.0.0 h1:0VngyaIyqACHdcMNWfo6+KdUYnqEr2Sg+bSP1pdF+dI=
github.com/cli/safeexec v1.0.0/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5zx3Q=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/coreos/bbolt v1.3.2 h1:wZwiHHUieZCquLkDL0B8UhzreNWsPHooDAG3q34zk0s=
Expand Down
10 changes: 7 additions & 3 deletions hugolib/js_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ package hugolib
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"runtime"
"testing"

"github.com/gohugoio/hugo/common/hexec"

"github.com/gohugoio/hugo/htesting"

"github.com/spf13/viper"
Expand Down Expand Up @@ -125,7 +126,9 @@ TS: {{ template "print" $ts }}

b.WithSourceFile("assets/js/included.js", includedJS)

out, err := exec.Command("npm", "install").CombinedOutput()
cmd, err := hexec.SafeCommand("npm", "install")
b.Assert(err, qt.IsNil)
out, err := cmd.CombinedOutput()
b.Assert(err, qt.IsNil, qt.Commentf(string(out)))

b.Build(BuildCfg{})
Expand Down Expand Up @@ -194,7 +197,8 @@ require github.com/gohugoio/hugoTestProjectJSModImports v0.5.0 // indirect
}`)

b.Assert(os.Chdir(workDir), qt.IsNil)
_, err = exec.Command("npm", "install").CombinedOutput()
cmd, _ := hexec.SafeCommand("npm", "install")
_, err = cmd.CombinedOutput()
b.Assert(err, qt.IsNil)

b.Build(BuildCfg{})
Expand Down
6 changes: 4 additions & 2 deletions hugolib/resource_chain_babel_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ package hugolib
import (
"bytes"
"os"
"os/exec"
"path/filepath"
"runtime"
"testing"

"github.com/gohugoio/hugo/common/hexec"

jww "github.com/spf13/jwalterweatherman"

"github.com/gohugoio/hugo/htesting"
Expand Down Expand Up @@ -111,7 +112,8 @@ Transpiled: {{ $transpiled.Content | safeJS }}
b.WithSourceFile("babel.config.js", babelConfig)

b.Assert(os.Chdir(workDir), qt.IsNil)
_, err = exec.Command("npm", "install").CombinedOutput()
cmd, _ := hexec.SafeCommand("npm", "install")
_, err = cmd.CombinedOutput()
b.Assert(err, qt.IsNil)

b.Build(BuildCfg{})
Expand Down
6 changes: 4 additions & 2 deletions hugolib/resource_chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ import (
"math/rand"
"os"

"os/exec"
"github.com/gohugoio/hugo/common/hexec"

"path/filepath"
"runtime"
"strings"
Expand Down Expand Up @@ -952,7 +953,8 @@ class-in-b {
b.WithSourceFile("postcss.config.js", postcssConfig)

b.Assert(os.Chdir(workDir), qt.IsNil)
_, err = exec.Command("npm", "install").CombinedOutput()
cmd, err := hexec.SafeCommand("npm", "install")
_, err = cmd.CombinedOutput()
b.Assert(err, qt.IsNil)
b.Build(BuildCfg{})

Expand Down
5 changes: 3 additions & 2 deletions markup/asciidocext/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ package asciidocext

import (
"bytes"
"os/exec"
"path/filepath"

"github.com/cli/safeexec"

"github.com/gohugoio/hugo/identity"
"github.com/gohugoio/hugo/markup/asciidocext/asciidocext_config"
"github.com/gohugoio/hugo/markup/converter"
Expand Down Expand Up @@ -194,7 +195,7 @@ func (a *asciidocConverter) appendArg(args []string, option, value, defaultValue
}

func getAsciidoctorExecPath() string {
path, err := exec.LookPath("asciidoctor")
path, err := safeexec.LookPath("asciidoctor")
if err != nil {
return ""
}
Expand Down
16 changes: 11 additions & 5 deletions markup/internal/external.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package internal

import (
"bytes"
"os/exec"
"strings"

"github.com/cli/safeexec"
"github.com/gohugoio/hugo/common/hexec"

"github.com/gohugoio/hugo/markup/converter"
)

Expand All @@ -14,12 +16,16 @@ func ExternallyRenderContent(
content []byte, path string, args []string) []byte {

logger := cfg.Logger
cmd := exec.Command(path, args...)
cmd, err := hexec.SafeCommand(path, args...)
if err != nil {
logger.Errorf("%s rendering %s: %v", path, ctx.DocumentName, err)
return nil
}
cmd.Stdin = bytes.NewReader(content)
var out, cmderr bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &cmderr
err := cmd.Run()
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") {
Expand All @@ -41,9 +47,9 @@ func normalizeExternalHelperLineFeeds(content []byte) []byte {
}

func GetPythonExecPath() string {
path, err := exec.LookPath("python")
path, err := safeexec.LookPath("python")
if err != nil {
path, err = exec.LookPath("python.exe")
path, err = safeexec.LookPath("python.exe")
if err != nil {
return ""
}
Expand Down
5 changes: 2 additions & 3 deletions markup/pandoc/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
package pandoc

import (
"os/exec"

"github.com/cli/safeexec"
"github.com/gohugoio/hugo/identity"
"github.com/gohugoio/hugo/markup/internal"

Expand Down Expand Up @@ -66,7 +65,7 @@ func (c *pandocConverter) getPandocContent(src []byte, ctx converter.DocumentCon
}

func getPandocExecPath() string {
path, err := exec.LookPath("pandoc")
path, err := safeexec.LookPath("pandoc")
if err != nil {
return ""
}
Expand Down
7 changes: 4 additions & 3 deletions markup/rst/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ package rst

import (
"bytes"
"os/exec"
"runtime"

"github.com/cli/safeexec"

"github.com/gohugoio/hugo/identity"
"github.com/gohugoio/hugo/markup/internal"

Expand Down Expand Up @@ -96,9 +97,9 @@ func (c *rstConverter) getRstContent(src []byte, ctx converter.DocumentContext)
}

func getRstExecPath() string {
path, err := exec.LookPath("rst2html")
path, err := safeexec.LookPath("rst2html")
if err != nil {
path, err = exec.LookPath("rst2html.py")
path, err = safeexec.LookPath("rst2html.py")
if err != nil {
return ""
}
Expand Down
7 changes: 6 additions & 1 deletion modules/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import (
"path/filepath"
"regexp"

"github.com/gohugoio/hugo/common/hexec"

hglob "github.com/gohugoio/hugo/hugofs/glob"

"github.com/gobwas/glob"
Expand Down Expand Up @@ -545,7 +547,10 @@ func (c *Client) runGo(
}

stderr := new(bytes.Buffer)
cmd := exec.CommandContext(ctx, "go", args...)
cmd, err := hexec.SafeCommandContext(ctx, "go", args...)
if err != nil {
return err
}

cmd.Env = c.environ
cmd.Dir = c.ccfg.WorkingDir
Expand Down
5 changes: 3 additions & 2 deletions releaser/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ package releaser

import (
"fmt"
"os/exec"
"regexp"
"sort"
"strconv"
"strings"

"github.com/gohugoio/hugo/common/hexec"
)

var issueRe = regexp.MustCompile(`(?i)[Updates?|Closes?|Fix.*|See] #(\d+)`)
Expand Down Expand Up @@ -148,7 +149,7 @@ func extractIssues(body string) []int {
type gitInfos []gitInfo

func git(args ...string) (string, error) {
cmd := exec.Command("git", args...)
cmd, _ := hexec.SafeCommand("git", args...)
out, err := cmd.CombinedOutput()
if err != nil {
return "", fmt.Errorf("git failed: %q: %q (%q)", err, out, args)
Expand Down
5 changes: 3 additions & 2 deletions releaser/releaser.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ import (
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"

"github.com/gohugoio/hugo/common/hexec"

"github.com/gohugoio/hugo/common/hugo"
"github.com/pkg/errors"
)
Expand Down Expand Up @@ -266,7 +267,7 @@ func (r *ReleaseHandler) release(releaseNotesFile string) error {
args = append(args, "--skip-publish")
}

cmd := exec.Command("goreleaser", args...)
cmd, _ := hexec.SafeCommand("goreleaser", args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
Expand Down
12 changes: 8 additions & 4 deletions resources/resource_transformers/babel/babel.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ package babel
import (
"bytes"
"io"
"os/exec"
"path/filepath"
"strconv"

"github.com/cli/safeexec"
"github.com/gohugoio/hugo/common/hexec"
"github.com/gohugoio/hugo/common/loggers"

"github.com/gohugoio/hugo/common/hugo"
Expand Down Expand Up @@ -107,10 +108,10 @@ func (t *babelTransformation) Transform(ctx *resources.ResourceTransformationCtx

binary := csiBinPath

if _, err := exec.LookPath(binary); err != nil {
if _, err := safeexec.LookPath(binary); err != nil {
// Try PATH
binary = binaryName
if _, err := exec.LookPath(binary); err != nil {
if _, err := safeexec.LookPath(binary); err != nil {

// This may be on a CI server etc. Will fall back to pre-built assets.
return herrors.ErrFeatureNotAvailable
Expand Down Expand Up @@ -152,7 +153,10 @@ func (t *babelTransformation) Transform(ctx *resources.ResourceTransformationCtx
}
cmdArgs = append(cmdArgs, "--filename="+ctx.SourcePath)

cmd := exec.Command(binary, cmdArgs...)
cmd, err := hexec.SafeCommand(binary, cmdArgs...)
if err != nil {
return err
}

cmd.Stdout = ctx.To
cmd.Stderr = io.MultiWriter(infoW, &errBuf)
Expand Down
Loading

0 comments on commit 4a8267d

Please sign in to comment.