Skip to content

Commit

Permalink
Support adding files from standard input
Browse files Browse the repository at this point in the history
Using a null char as separator, which allows files with e.g. commas or
end-of-line characters in their names.
  • Loading branch information
sanmai-NL committed Dec 15, 2023
1 parent 1c362e3 commit 3bb48b9
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 5 deletions.
5 changes: 5 additions & 0 deletions cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ func newRunCmd(opts *lefthook.Options) *cobra.Command {
"run hooks on all files",
)

runCmd.Flags().BoolVar(
&runArgs.FilesFromStdin, "files-from-stdin", false,
"get files from standard input, null-separated, instead of from CLI parameters --file(s)",
)

runCmd.Flags().StringSliceVar(&runArgs.Files, "files", nil, "[DEPRECATED] run on specified files, comma-separated. takes precedence over --all-files")

runCmd.Flags().StringArrayVar(&runArgs.Files, "file", nil, "run on specified file (repeat for multiple files). takes precedence over --all-files")
Expand Down
9 changes: 5 additions & 4 deletions internal/config/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@ type Command struct {
Exclude string `mapstructure:"exclude" yaml:",omitempty" json:"exclude,omitempty" toml:"exclude,omitempty"`
Priority int `mapstructure:"priority" yaml:",omitempty" json:"priority,omitempty" toml:"priority,omitempty"`

FailText string `mapstructure:"fail_text" yaml:"fail_text,omitempty" json:"fail_text,omitempty" toml:"fail_text,omitempty"`
Interactive bool `mapstructure:"interactive" yaml:",omitempty" json:"interactive,omitempty" toml:"interactive,omitempty"`
UseStdin bool `mapstructure:"use_stdin" yaml:",omitempty" json:"use_stdin,omitempty" toml:"use_stdin,omitempty"`
StageFixed bool `mapstructure:"stage_fixed" yaml:"stage_fixed,omitempty" json:"stage_fixed,omitempty" toml:"stage_fixed,omitempty"`
FailText string `mapstructure:"fail_text" yaml:"fail_text,omitempty" json:"fail_text,omitempty" toml:"fail_text,omitempty"`
Interactive bool `mapstructure:"interactive" yaml:",omitempty" json:"interactive,omitempty" toml:"interactive,omitempty"`
UseStdin bool `mapstructure:"use_stdin" yaml:",omitempty" json:"use_stdin,omitempty" toml:"use_stdin,omitempty"`
StageFixed bool `mapstructure:"stage_fixed" yaml:"stage_fixed,omitempty" json:"stage_fixed,omitempty" toml:"stage_fixed,omitempty"`
FilesFromStdin bool `mapstructure:"files_from_stdin" yaml:",omitempty" json:"files_from_stdin,omitempty" toml:"files_from_stdin,omitempty"`
}

func (c Command) Validate() error {
Expand Down
2 changes: 2 additions & 0 deletions internal/lefthook/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const (
type RunArgs struct {
NoTTY bool
AllFiles bool
FilesFromStdin bool
Force bool
Files []string
RunOnlyCommands []string
Expand Down Expand Up @@ -124,6 +125,7 @@ Run 'lefthook install' manually.`,
SkipSettings: logSettings,
DisableTTY: cfg.NoTTY || args.NoTTY,
AllFiles: args.AllFiles,
FilesFromStdin: args.FilesFromStdin,
Files: args.Files,
Force: args.Force,
RunOnlyCommands: args.RunOnlyCommands,
Expand Down
31 changes: 30 additions & 1 deletion internal/lefthook/run/prepare_command.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package run

import (
"bufio"
"errors"
"fmt"
"os"
"runtime"
"strings"

Expand Down Expand Up @@ -64,8 +66,35 @@ func (r *Runner) prepareCommand(name string, command *config.Command) (*run, err
return args, nil
}

func splitNullTerminatedPaths(s string) []string {
var result []string
start := 0
for i, c := range s {
if c == 0 {
result = append(result, s[start:i])
start = i + 1
}
}
result = append(result, s[start:])
return result
}

func (r *Runner) buildRun(command *config.Command) (*run, error, error) {
filesCmd := r.Hook.Files
if command.FilesFromStdin || r.FilesFromStdin {
scanner := bufio.NewScanner(os.Stdin)
scanner.Split(bufio.ScanLines)

for scanner.Scan() {
line := scanner.Text()
r.Files = splitNullTerminatedPaths(line)
}

if err := scanner.Err(); err != nil {
return nil, fmt.Errorf("error reading standard input: %w", err), nil
}
}

if len(command.Files) > 0 {
filesCmd = command.Files
}
Expand Down Expand Up @@ -105,7 +134,7 @@ func (r *Runner) buildRun(command *config.Command) (*run, error, error) {

files, err := fn()
if err != nil {
return nil, fmt.Errorf("error replacing %s: %w", filesType, err), nil
return nil, fmt.Errorf("failed to read file paths from standard input: %w", err), nil
}

files = filter.Apply(command, files)
Expand Down
1 change: 1 addition & 0 deletions internal/lefthook/run/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ type Options struct {
SkipSettings log.SkipSettings
DisableTTY bool
AllFiles bool
FilesFromStdin bool
Force bool
Files []string
RunOnlyCommands []string
Expand Down

0 comments on commit 3bb48b9

Please sign in to comment.