1// Copyright (c) 2024, Google Inc. 2// 3// Permission to use, copy, modify, and/or distribute this software for any 4// purpose with or without fee is hereby granted, provided that the above 5// copyright notice and this permission notice appear in all copies. 6// 7// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 10// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 12// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 13// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 15package main 16 17import ( 18 "bytes" 19 "os" 20 "os/exec" 21 "path" 22 "path/filepath" 23) 24 25type Task interface { 26 // Destination returns the destination path for this task, using forward 27 // slashes and relative to the source directory. That is, use the "path" 28 // package, not "path/filepath". 29 Destination() string 30 31 // Run computes the output for this task. It should be written to the 32 // destination path. 33 Run() ([]byte, error) 34} 35 36type SimpleTask struct { 37 Dst string 38 RunFunc func() ([]byte, error) 39} 40 41func (t *SimpleTask) Destination() string { return t.Dst } 42func (t *SimpleTask) Run() ([]byte, error) { return t.RunFunc() } 43 44func NewSimpleTask(dst string, runFunc func() ([]byte, error)) *SimpleTask { 45 return &SimpleTask{Dst: dst, RunFunc: runFunc} 46} 47 48type PerlasmTask struct { 49 Src, Dst string 50 Args []string 51} 52 53func (t *PerlasmTask) Destination() string { return t.Dst } 54func (t *PerlasmTask) Run() ([]byte, error) { 55 base := path.Base(t.Dst) 56 out, err := os.CreateTemp("", "*."+base) 57 if err != nil { 58 return nil, err 59 } 60 defer os.Remove(out.Name()) 61 62 args := make([]string, 0, 2+len(t.Args)) 63 args = append(args, filepath.FromSlash(t.Src)) 64 args = append(args, t.Args...) 65 args = append(args, out.Name()) 66 cmd := exec.Command(*perlPath, args...) 67 cmd.Stderr = os.Stderr 68 cmd.Stdout = os.Stdout 69 if err := cmd.Run(); err != nil { 70 return nil, err 71 } 72 73 data, err := os.ReadFile(out.Name()) 74 if err != nil { 75 return nil, err 76 } 77 78 // On Windows, perl emits CRLF line endings. Normalize this so that the tool 79 // can be run on Windows too. 80 data = bytes.ReplaceAll(data, []byte("\r\n"), []byte("\n")) 81 return data, nil 82} 83