| 60 | var cmdArgExtension = regexp.MustCompile(`^\.[0-9a-zA-Z]+`) |
| 61 | |
| 62 | func (c *cmdMinifier) Minify(_ *M, w io.Writer, r io.Reader, _ map[string]string) error { |
| 63 | cmd := &exec.Cmd{} |
| 64 | *cmd = *c.cmd // concurrency safety |
| 65 | |
| 66 | var in, out *os.File |
| 67 | for i, arg := range cmd.Args { |
| 68 | if j := strings.Index(arg, "$in"); j != -1 { |
| 69 | var err error |
| 70 | ext := cmdArgExtension.FindString(arg[j+3:]) |
| 71 | if in != nil { |
| 72 | return fmt.Errorf("more than one input arguments") |
| 73 | } else if in, err = os.CreateTemp("", "minify-in-*"+ext); err != nil { |
| 74 | return err |
| 75 | } |
| 76 | defer func() { |
| 77 | os.Remove(in.Name()) |
| 78 | }() |
| 79 | cmd.Args[i] = arg[:j] + in.Name() + arg[j+3+len(ext):] |
| 80 | } else if j := strings.Index(arg, "$out"); j != -1 { |
| 81 | var err error |
| 82 | ext := cmdArgExtension.FindString(arg[j+4:]) |
| 83 | if out != nil { |
| 84 | return fmt.Errorf("more than one output arguments") |
| 85 | } else if out, err = os.CreateTemp("", "minify-out-*"+ext); err != nil { |
| 86 | return err |
| 87 | } |
| 88 | defer func() { |
| 89 | os.Remove(out.Name()) |
| 90 | }() |
| 91 | cmd.Args[i] = arg[:j] + out.Name() + arg[j+4+len(ext):] |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | if in == nil { |
| 96 | cmd.Stdin = r |
| 97 | } else if _, err := io.Copy(in, r); err != nil { |
| 98 | return err |
| 99 | } |
| 100 | if out == nil { |
| 101 | cmd.Stdout = w |
| 102 | } else { |
| 103 | defer io.Copy(w, out) |
| 104 | } |
| 105 | stderr := &bytes.Buffer{} |
| 106 | cmd.Stderr = stderr |
| 107 | |
| 108 | err := cmd.Run() |
| 109 | if _, ok := err.(*exec.ExitError); ok { |
| 110 | if stderr.Len() != 0 { |
| 111 | err = fmt.Errorf("%s", stderr.String()) |
| 112 | } |
| 113 | err = fmt.Errorf("command %s failed: %w", cmd.Path, err) |
| 114 | } |
| 115 | return err |
| 116 | } |
| 117 | |
| 118 | //////////////////////////////////////////////////////////////// |
| 119 | |