Skip to content

Commit

Permalink
fix: auto split files into chunks
Browse files Browse the repository at this point in the history
  • Loading branch information
mrexox committed Aug 25, 2023
1 parent c8ff4be commit 84ff44d
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 67 deletions.
56 changes: 34 additions & 22 deletions internal/lefthook/runner/execute_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,35 +20,55 @@ import (
type CommandExecutor struct{}

func (e CommandExecutor) Execute(opts ExecuteOptions, out io.Writer) error {
stdin := os.Stdin
in := os.Stdin
if opts.interactive && !isatty.IsTerminal(os.Stdin.Fd()) {
tty, err := os.Open("/dev/tty")
if err == nil {
defer tty.Close()
stdin = tty
in = tty
} else {
log.Errorf("Couldn't enable TTY input: %s\n", err)
}
}

command := exec.Command("sh", "-c", strings.Join(opts.args, " "))

rootDir, _ := filepath.Abs(opts.root)
command.Dir = rootDir

envList := make([]string, len(opts.env))
root, _ := filepath.Abs(opts.root)
envs := make([]string, len(opts.env))
for name, value := range opts.env {
envList = append(
envList,
envs = append(
envs,
fmt.Sprintf("%s=%s", strings.ToUpper(name), os.ExpandEnv(value)),
)
}

command.Env = append(os.Environ(), envList...)
// We can have one command split into separate to fit into shell command max length.
// In this case we execute those commands one by one.
for _, args := range opts.commands {
if err := e.executeOne(args, root, envs, opts.interactive, in, out); err != nil {
return err
}
}

return nil

}

func (e CommandExecutor) RawExecute(command []string, out io.Writer) error {
cmd := exec.Command(command[0], command[1:]...)

cmd.Stdout = out
cmd.Stderr = os.Stderr

return cmd.Run()
}

if opts.interactive {
func (e CommandExecutor) executeOne(args []string, root string, envs []string, interactive bool, in io.Reader, out io.Writer) error {
command := exec.Command("sh", "-c", strings.Join(args, " "))
command.Dir = root
command.Env = append(os.Environ(), envs...)

if interactive {
command.Stdout = out
command.Stdin = stdin
command.Stdin = in
command.Stderr = os.Stderr
err := command.Start()
if err != nil {
Expand All @@ -62,21 +82,13 @@ func (e CommandExecutor) Execute(opts ExecuteOptions, out io.Writer) error {

defer func() { _ = p.Close() }()

go func() { _, _ = io.Copy(p, stdin) }()
go func() { _, _ = io.Copy(p, in) }()

_, _ = io.Copy(out, p)
}

defer func() { _ = command.Process.Kill() }()

return command.Wait()
}

func (e CommandExecutor) RawExecute(command []string, out io.Writer) error {
cmd := exec.Command(command[0], command[1:]...)

cmd.Stdout = out
cmd.Stderr = os.Stderr

return cmd.Run()
}
54 changes: 31 additions & 23 deletions internal/lefthook/runner/execute_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,31 +13,48 @@ import (
type CommandExecutor struct{}

func (e CommandExecutor) Execute(opts ExecuteOptions, out io.Writer) error {
command := exec.Command(opts.args[0])
command.SysProcAttr = &syscall.SysProcAttr{
CmdLine: strings.Join(opts.args, " "),
}

rootDir, _ := filepath.Abs(opts.root)
command.Dir = rootDir

envList := make([]string, len(opts.env))
root, _ := filepath.Abs(opts.root)
envs := make([]string, len(opts.env))
for name, value := range opts.env {
envList = append(
envList,
envs = append(
envs,
fmt.Sprintf("%s=%s", strings.ToUpper(name), os.ExpandEnv(value)),
)
}

command.Env = append(os.Environ(), envList...)
for _, args := range opts.commands {
if err := e.executeOne(args, root, envs, opts.interactive, os.Stdin, out); err != nil {
return err
}
}

return nil
}

func (e CommandExecutor) RawExecute(command []string, out io.Writer) error {
cmd := exec.Command(command[0], command[1:]...)

cmd.Stdout = out
cmd.Stderr = os.Stderr

return cmd.Run()
}

if opts.interactive {
func (e CommandExecutor) executeOne(args []string, root string, envs []string, interactive bool, in io.Reader, out io.Writer) error {
command := exec.Command(args)

Check failure on line 44 in internal/lefthook/runner/execute_windows.go

View workflow job for this annotation

GitHub Actions / build

cannot use args (variable of type []string) as string value in argument to exec.Command
command.SysProcAttr = &syscall.SysProcAttr{
CmdLine: strings.Join(args, " "),
}
command.Dir = root
command.Env = append(os.Environ(), envs...)

if interactive {
command.Stdout = os.Stdout
} else {
command.Stdout = out
}

command.Stdin = os.Stdin
command.Stdin = in
command.Stderr = os.Stderr
err := command.Start()
if err != nil {
Expand All @@ -48,12 +65,3 @@ func (e CommandExecutor) Execute(opts ExecuteOptions, out io.Writer) error {

return command.Wait()
}

func (e CommandExecutor) RawExecute(command []string, out io.Writer) error {
cmd := exec.Command(command[0], command[1:]...)

cmd.Stdout = out
cmd.Stderr = os.Stderr

return cmd.Run()
}
2 changes: 1 addition & 1 deletion internal/lefthook/runner/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
// ExecutorOptions contains the options that control the execution.
type ExecuteOptions struct {
name, root, failText string
args []string
commands [][]string
env map[string]string
interactive bool
}
Expand Down
36 changes: 19 additions & 17 deletions internal/lefthook/runner/prepare_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ import (
"github.com/evilmartians/lefthook/internal/log"
)

type commandArgs struct {
all []string
files []string
// An object that described the single command's run option.
type run struct {
commands [][]string
files []string
}

func (r *Runner) prepareCommand(name string, command *config.Command) (*commandArgs, error) {
func (r *Runner) prepareCommand(name string, command *config.Command) (*run, error) {
if command.DoSkip(r.Repo.State()) {
return nil, errors.New("settings")
}
Expand All @@ -34,7 +35,7 @@ func (r *Runner) prepareCommand(name string, command *config.Command) (*commandA
return nil, errors.New("invalid config")
}

args, err, skipReason := r.buildCommandArgs(command)
args, err, skipReason := r.buildRun(command)
if err != nil {
log.Error(err)
return nil, errors.New("error")
Expand All @@ -46,26 +47,28 @@ func (r *Runner) prepareCommand(name string, command *config.Command) (*commandA
return args, nil
}

func (r *Runner) buildCommandArgs(command *config.Command) (*commandArgs, error, error) {
filesCommand := r.Hook.Files
if command.Files != "" {
filesCommand = command.Files
func (r *Runner) buildRun(command *config.Command) (*run, error, error) {
filesCmd := r.Hook.Files
if len(command.Files) > 0 {
filesCmd = command.Files
}

stagedFiles := r.Repo.StagedFiles
var stagedFiles func() ([]string, error)
if len(r.Files) > 0 {
stagedFiles = func() ([]string, error) { return r.Files, nil }
} else if r.AllFiles {
stagedFiles = r.Repo.AllFiles
} else {
stagedFiles = r.Repo.StagedFiles
}

filesTypeToFn := map[string]func() ([]string, error){
config.SubStagedFiles: stagedFiles,
config.PushFiles: r.Repo.PushFiles,
config.SubAllFiles: r.Repo.AllFiles,
config.SubFiles: func() ([]string, error) {
filesCommand = r.replacePositionalArguments(filesCommand)
return r.Repo.FilesByCommand(filesCommand)
filesCmd = r.replacePositionalArguments(filesCmd)
return r.Repo.FilesByCommand(filesCmd)
},
}

Expand All @@ -76,8 +79,7 @@ func (r *Runner) buildCommandArgs(command *config.Command) (*commandArgs, error,
//
// Special case - `files` option: return if the result of files
// command is empty.
if strings.Contains(runString, filesType) ||
filesCommand != "" && filesType == config.SubFiles {
if strings.Contains(runString, filesType) || len(filesCmd) > 0 && filesType == config.SubFiles {
files, err := filesFn()
if err != nil {
return nil, fmt.Errorf("error replacing %s: %w", filesType, err), nil
Expand Down Expand Up @@ -120,9 +122,9 @@ func (r *Runner) buildCommandArgs(command *config.Command) (*commandArgs, error,

log.Debug("[lefthook] executing: ", runString)

return &commandArgs{
files: filesFiltered,
all: strings.Split(runString, " "),
return &run{
commands: [][]string{strings.Split(runString, " ")},
files: filesFiltered,
}, nil, nil
}

Expand Down
8 changes: 4 additions & 4 deletions internal/lefthook/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ func (r *Runner) runScript(script *config.Script, path string, file os.FileInfo)
finished := r.run(ExecuteOptions{
name: file.Name(),
root: r.Repo.RootPath,
args: args,
commands: [][]string{args},
failText: script.FailText,
interactive: script.Interactive && !r.DisableTTY,
env: script.Env,
Expand Down Expand Up @@ -356,7 +356,7 @@ func (r *Runner) runCommands() {
}

func (r *Runner) runCommand(name string, command *config.Command) {
args, err := r.prepareCommand(name, command)
run, err := r.prepareCommand(name, command)
if err != nil {
r.logSkip(name, err.Error())
return
Expand All @@ -370,14 +370,14 @@ func (r *Runner) runCommand(name string, command *config.Command) {
finished := r.run(ExecuteOptions{
name: name,
root: filepath.Join(r.Repo.RootPath, command.Root),
args: args.all,
commands: run.commands,
failText: command.FailText,
interactive: command.Interactive && !r.DisableTTY,
env: command.Env,
}, r.Hook.Follow)

if finished && config.HookUsesStagedFiles(r.HookName) && command.StageFixed {
files := args.files
files := run.files

if len(files) == 0 {
var err error
Expand Down

0 comments on commit 84ff44d

Please sign in to comment.