all repos

viye @ f1413a3

my shot at reimplementing xiki
2 files changed, 116 insertions(+), 0 deletions(-)
add make tool
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
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)