diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f7b3492 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index 97e619c..9f5da9d 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -11,9 +11,9 @@ "mode": "auto", "program": "${fileDirname}", "args": [ - "tar" + "targetx" ], - "cwd": "./test1" + "cwd": "./example/subfolder" } ] } \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..181b789 --- /dev/null +++ b/Dockerfile @@ -0,0 +1 @@ +FROM hello-world \ No newline at end of file diff --git a/Makefile b/Makefile deleted file mode 100644 index c65c7c1..0000000 --- a/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -PHONY: targetx -targetx: - echo "Hello there" - exit 1 - echo "should not make it" - - - -## This is a special rule that enables the use of -## $(filter-out $@,$(MAKECMDGOALS)) -## '%:' is a rule that matches anything -## '@:' is a recipe that does nothing -## the @ means 'do it silently' -## in short: If recipe can't be found, do nothing and do it silently -%: - @: diff --git a/example/Makefile b/example/Makefile new file mode 100644 index 0000000..cff615a --- /dev/null +++ b/example/Makefile @@ -0,0 +1,3 @@ +PHONY: targetx +targetx: + docker build ../ diff --git a/example/subfolder/Makefile b/example/subfolder/Makefile new file mode 100644 index 0000000..fe1d7a2 --- /dev/null +++ b/example/subfolder/Makefile @@ -0,0 +1,3 @@ +PHONY: targetx +targety: + echo "Hello Y" diff --git a/go.mod b/go.mod index 89440f8..146d394 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module maker go 1.16 + +require github.com/creack/pty v1.1.13 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..f3c6ee9 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/creack/pty v1.1.13 h1:rTPnd/xocYRjutMfqide2zle1u96upp1gm6eUHKi7us= +github.com/creack/pty v1.1.13/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= diff --git a/main.go b/main.go index 52c08f7..557401d 100644 --- a/main.go +++ b/main.go @@ -1,109 +1,90 @@ package main import ( - "bufio" "errors" "fmt" + "io" "io/ioutil" "log" "os" "os/exec" - "strings" + "regexp" + + "github.com/creack/pty" ) -func runMake(dir string, args ...string) error { - dirCommand := []string{"-C", dir} - allArgs := append(dirCommand, args...) - cmd := exec.Command("make", allArgs...) - stdout, err := cmd.StdoutPipe() - if err != nil { - log.Fatal(err) - } - - stderr, err := cmd.StderrPipe() +func makefileHasTarget(target string, path string) (bool, error) { + fileContent, err := ioutil.ReadFile(path) if err != nil { - log.Fatal(err) - } - - if err := cmd.Start(); err != nil { - log.Fatal(err) + return false, err } - scannerOut := bufio.NewScanner(stdout) - scannerOut.Split(bufio.ScanLines) - - scannerErr := bufio.NewScanner(stderr) - scannerErr.Split(bufio.ScanLines) - - go func() { - for scannerOut.Scan() { - m := scannerOut.Text() - fmt.Println(m) - } - }() - - for scannerErr.Scan() { - m := scannerErr.Text() - fmt.Println(m) - } - + stringMatch := fmt.Sprintf(`\n?%s:`, target) + return regexp.Match(stringMatch, fileContent) +} - if err := cmd.Wait(); err != nil { - log.Fatal(err) +func exists(name string) (bool, error) { + _, err := os.Stat(name) + if errors.Is(err, os.ErrNotExist) { + return false, nil } - - return nil + return err == nil, err } +func findMakeFileWithTarget(cwd, target string) (string, error) { + hasMakefile, err := exists(cwd + "Makefile") + if err != nil { + return "", err + } + if hasMakefile { + commandExists, err := makefileHasTarget(target, cwd + "Makefile") + if err != nil { + return "", err + } -func checkIfCommandExists(command string, path string) (bool, error) { - fileContent, err := ioutil.ReadFile(path) - - if os.IsNotExist(err) { - return false, nil - } else if err != nil { - return false, err + if commandExists { + return cwd, nil + } } - fileContentString := string(fileContent) - stringMatch := fmt.Sprintf("PHONY:%s\n%s:", command, command) - if strings.Contains(strings.ReplaceAll(fileContentString, " ", ""), stringMatch) { - return true, nil + + if isGitRoot, _ := exists(cwd + ".git"); !isGitRoot { + return findMakeFileWithTarget("./." + cwd, target) } - return false, nil + + return "", errors.New("Could not find a makefile with target: " + target) } +func runMake(dir string, args ...string) error { + dirCommand := []string{"-C", dir} + allArgs := append(dirCommand, args...) + cmd := exec.Command("make", allArgs...) + + f, err := pty.Start(cmd) + if err != nil { + return err + } -func runRecurse(cwd string) error { - commandExists, err := checkIfCommandExists(os.Args[1], cwd + "Makefile") - if err != nil { - return err - } else if commandExists { - err := runMake(cwd, os.Args[1:]...) - return err - } else if _, err := os.Stat(cwd + ".git"); os.IsNotExist(err) { - err := runRecurse("./." + cwd) - if err != nil { - return err - } - } else { - return errors.New("Could not find a makefile with target: " + os.Args[1]) - } + io.Copy(os.Stdout, f) return nil } func main() { if len(os.Args[1:]) < 1 { - fmt.Println("You must provide a make target") - return + log.Fatalln("You must provide a make target") + } + + makeFileDir, err := findMakeFileWithTarget("./", os.Args[1]) + if err != nil { + log.Fatalln("Could not find a makefile:", err.Error()) } - err := runRecurse("./") + err = runMake(makeFileDir, os.Args[1:]...) if err != nil { - fmt.Println("An error occurred while running make:", err.Error()) + log.Fatalln("Could not run makefile:", err.Error()) } } \ No newline at end of file