2 files changed,
116 insertions(+),
0 deletions(-)
Author:
Oleksandr Smirnov
olexsmir@gmail.com
Committed at:
2026-08-25 17:20:38 +0300
Authored at:
2026-08-25 12:37:40 +0300
Change ID:
xxwknmylqszrwlktzolwsylvuwwvrlvt
Parent:
d364a1e
jump to
| A | internal/plumbing/makefile/makefile.go |
| M | main.go |
A
internal/plumbing/makefile/makefile.go
··· 1 +package makefile 2 + 3 +import ( 4 + "bufio" 5 + "bytes" 6 + "errors" 7 + "os" 8 + "os/exec" 9 + "path/filepath" 10 + "slices" 11 + "strings" 12 + 13 + "github.com/olexsmir/viye/internal/viye" 14 +) 15 + 16 +var ErrMakefileNotFound = errors.New("makefile not found") 17 + 18 +type Tool struct{} 19 + 20 +func (Tool) Name() string { return "make" } 21 +func (Tool) Match(c *viye.Context) bool { return c.Cmd == "make" } 22 +func (Tool) Execute(c *viye.Context) (string, error) { 23 + fpath, found := findMakefile(c) 24 + if !found { 25 + return "", ErrMakefileNotFound 26 + } 27 + 28 + contents, err := os.ReadFile(fpath) 29 + if err != nil { 30 + return "", err 31 + } 32 + 33 + tasks, err := listTasksFromMakefile(contents) 34 + if err != nil { 35 + return "", err 36 + } 37 + 38 + switch len(c.Args) { 39 + case 0: // list make file tasks 40 + return viye.FormatBulletList(tasks), nil 41 + 42 + case 1: // run specified task 43 + if !slices.Contains(tasks, c.Args[0]) { 44 + return "", ErrTaskNotFound 45 + } 46 + cmd := exec.Command("make", c.Args[0]) 47 + cmd.Dir = c.Dir 48 + out, err := cmd.Output() 49 + if err != nil { 50 + return "", err 51 + } 52 + return viye.FormatOutput(string(out)), nil 53 + 54 + default: 55 + return "", errors.New("invalid command, make usage: make [task]") 56 + } 57 +} 58 + 59 +var ErrTaskNotFound = errors.New("task not found") 60 + 61 +func findMakefile(c *viye.Context) (name string, found bool) { 62 + for _, mfile := range []string{"makefile", "Makefile", "GNUMakefile"} { 63 + path := filepath.Join(c.Dir, mfile) 64 + if _, err := os.Stat(path); err == nil { 65 + return path, true 66 + } 67 + } 68 + return "", false 69 +} 70 + 71 +func listTasksFromMakefile(contents []byte) ([]string, error) { 72 + var tasks []string 73 + scanner := bufio.NewScanner(bytes.NewReader(contents)) 74 + for scanner.Scan() { 75 + line := scanner.Text() 76 + 77 + if len(line) == 0 || line[0] == '\t' || line[0] == ' ' { 78 + continue 79 + } 80 + if strings.HasPrefix(line, "#") { // comments 81 + continue 82 + } 83 + 84 + colon := strings.IndexByte(line, ':') 85 + if colon <= 0 { 86 + continue 87 + } 88 + 89 + name := strings.TrimSpace(line[:colon]) 90 + if name == "" { 91 + continue 92 + } 93 + 94 + rest := line[colon+1:] 95 + if strings.HasPrefix(rest, "=") { // variable assigments 96 + continue 97 + } 98 + if strings.HasPrefix(rest, ":") { // ::= or double-colon rule 99 + rest = rest[1:] 100 + if strings.HasPrefix(rest, "=") { 101 + continue 102 + } 103 + } 104 + 105 + if strings.Contains(name, "%") || strings.HasPrefix(name, ".") { // pattern rules and special targets 106 + continue 107 + } 108 + 109 + for n := range strings.FieldsSeq(name) { 110 + tasks = append(tasks, n) 111 + } 112 + } 113 + return tasks, nil 114 +}
M
main.go
··· 9 9 "github.com/olexsmir/viye/internal/plumbing/gobin" 10 10 "github.com/olexsmir/viye/internal/plumbing/ip" 11 11 "github.com/olexsmir/viye/internal/plumbing/json" 12 + "github.com/olexsmir/viye/internal/plumbing/makefile" 12 13 "github.com/olexsmir/viye/internal/plumbing/neofetch" 13 14 "github.com/olexsmir/viye/internal/plumbing/shell" 14 15 "github.com/olexsmir/viye/internal/plumbing/url" ··· 25 26 v.Register(&json.Tool{}) 26 27 v.Register(&config.Tool{}) 27 28 v.Register(&neofetch.Tool{}) 29 + v.Register(&makefile.Tool{}) 28 30 29 31 if err := v.Run(os.Stdout, os.Args); err != nil { 30 32 fmt.Fprintf(os.Stderr, "viye: %v\n", err)