mvdan / sh

A shell parser, formatter, and interpreter with bash support; includes shfmt
https://pkg.go.dev/mvdan.cc/sh/v3
BSD 3-Clause "New" or "Revised" License
7.28k stars 345 forks source link

Start a related project to parse and format Makefiles #730

Closed lassik closed 1 month ago

lassik commented 3 years ago

There now exist dozens of autoformatters covering almost every popular language but I can't find one for makefiles.

Makefiles most declare build targets, with a small shell script written beneath each target. Hence it looks like the problem of makefile formatting boils down to a relatively simple make formatter which calls a complex shell formatter as a subroutine to do most of the actual work.

Given that shfmt already has excellent coverage of shell, would it interest you to try adding a makefile wrapper around it?

mvdan commented 3 years ago

There are quite a lot of languages which are relatively thin wrappers over shell, like Makefile and Dockerfile. I agree it feels like a nice fit for parsing and even formatting.

We do something kinda similar for Bats right now; it's an extension of the bash language for testing, and adds @test as a reserved word for that purpose. Supporting that in the parser is trivial, and just adds one node type. One can also argue that supporting Bats directly is reasonable, since it's the de facto standard for testing shell code.

Makefile (and by extension Dockerfile etc) are a bit less clear to me, because they are less directly related to developing shell code, and add significantly more syntax of their own. Makefile adds the target: blocks, annotations like .PHONY: target, as well as their own assignments like FOO = bar with multiple operators including :=. They even seem to have their own conditionals with ifeq. I'm just scratching the surface here, and it seems like adding Makefile support in the syntax package would easily add 10 times as much code as Bats support did.

All that said, I think it would be a very good idea to start a project building on top of this module's syntax package to parse and format Makefiles (or Dockerfiles etc). For example, see https://github.com/jessfraz/dockfmt/issues/2. I'm more than happy to help out where I can, such as by improving the API if that is needed to integrate better at a low level.

I personally think that "Makefile parser+formatter" idea belongs in a different repository, simply because I do not have the bandwidth to write and maintain it myself, and do not want to become a bottleneck. I hope that makes sense. We could link these closely related projects in the README, though - see https://github.com/mvdan/sh#related-projects :)

lassik commented 3 years ago

Thanks for the encouraging response! That sounds like a good plan.

I probably won't have time to write a makefmt, but for anyone who wants to try it, GNU make probably has the most complex syntax of the various make variants floating around. Here are the key parts:

Line splitting is handled differently in recipes (i.e. embedded shell scripts) and non-recipe parts.

It looks like the most obvious strategy for formatting all that is to read in "logical lines" and tokenize each line. Then write out the tokens (space-separated in most case), starting a new line when a token would go over the width limit.

Some projects use makefiles where the recipes are written in Windows batch file (cmd.exe) syntax, so it may be prudent to add an option for that at some point.

lassik commented 3 years ago

Bonus: here's the POSIX make specification, written in manpage style.

mvdan commented 3 years ago

Sounds good, thanks for the info. I've repurposed the issue to see if anyone would be interested in starting this; we can leave it open for a while and see.

mvdan commented 1 month ago

It has been three years; it's time to close this as there is no interest. I'm still happy to assist here and there if someone wants to take this on, but it doesn't make sense to track it here.