tfausak / cabal-gild

:crown: Format Haskell package descriptions.
https://hackage.haskell.org/package/cabal-gild
MIT License
48 stars 5 forks source link

Supply an "inplace" mode #35

Closed turion closed 6 months ago

turion commented 8 months ago

To modify a cabal file in place, one currently needs to supply it as --input and --output. It would be easier if there was an option where one has to supply the file name only once. For example, this would allow usage like this:

cabal-gild --inplace=*/*.cabal

This is currently not directly possible, and one needs to resort to for loops or find.

turion commented 8 months ago

Workaround on linux is:

find . -name *.cabal -exec cabal-gild --input {} --output {} \;
tfausak commented 8 months ago

Thanks for opening this issue! I think there are actually two related feature requests here:

Alternatively, I could see adding something like --auto that discovers package descriptions and formats them in-place. Perhaps that's a little too magical though.

For this particular example, you can use the shell directly rather than find:

$ sh -exc 'for f in */*.cabal; do cabal-gild -i $f -o $f; done'
tfausak commented 8 months ago

Gild could add a new --io=FILE option for specifying both --input=FILE and --output=FILE at the same time. That would effectively be in-place. However it's still limited to one file, so you'd still have to script it somehow.

I'm trying to think of how to support this without dramatically changing the command line interface. I could add a new --inplace=FILES option, but it would be mutually incompatible with all the current options. And maybe people want to check multiple files instead of formatting them, in which case the --inplace option wouldn't be useful to them.

On the other hand, I tried to make Gild easy to use in shell scripts. Formatting (or checking) multiple package descriptions is a relatively advanced workflow, so perhaps requiring a shell script isn't outrageous.

turion commented 8 months ago

Ormolu for example has --mode=inplace. But that would make no big difference, since there would still have to be a separate way to specify multiple files. E.g.

gild --mode=inplace */*.cabal

This would be a bigger change to the CLI.

requiring a shell script isn't outrageous.

Not outrageous, it's just an extra hurdle to overcome. Maybe it's just me, but when I write Haskell, I want to write only Haskell, and not script my way around other things.

turion commented 8 months ago

And maybe people want to check multiple files instead of formatting them

So why not a usage like

gild --mode=check --input file1.cabal file2.cabal

You might even allow lists for --input and --output, but then requiring them to be of the same length? E.g.:

gild --input */*.cabal --output */*.cabal
turion commented 8 months ago

Formatting (or checking) multiple package descriptions is a relatively advanced workflow, so perhaps requiring a shell script isn't outrageous.

I guess you have a good point here. I just required gild for one of my projects (https://github.com/turion/rhine/pull/292) and my CI even turned out already to have a script that calls cabal check already, and it wasn't too hard to modify it to also call cabal-gild. (Although one might argue that cabal check should work for such a setup as well.)

Now that I think about it even more, maybe a possibility would be to call it for a cabal.project? It could extract several cabal files from there. Although one would need to add functionality to only take all local cabal files, as a cabal.project can contain references to arbitrary paths, even remote git repos.

tfausak commented 8 months ago

Yeah, I could allow both --input and --output to be specified multiple times, then zip them together pairwise. That would be clunky though. And I don't think it would solve your problem; even though you can say --input=*/*.cabal --output=*/*.cabal, I don't think the expansion order of globs is specified so in theory they could be mismatched.

Reading the cabal.project file to discover *.cabal files could work. That's what I meant to suggest with my --auto idea earlier. One problem with that approach is that Gild can also be used to format cabal.project files themselves. So there would need to be some way to distinguish between using a project file for discovery versus using it for formatting.

turion commented 8 months ago

I see, tricky. Maybe adding a pragma comment in cabal.project itself to specify those cabal files that should be matched and processed in the same way as the cabal.project is processed?

tfausak commented 8 months ago

I'm still not sure if I want to support this or not. However if I do, I think it will be like this:

Change the CLI to accept input as positional arguments. If there are no input files, read from STDIN. Remove the --input and --output options. Add a new mode called in-place that formats the input files in-place. For the regular format mode, output will be sent to STDOUT. Then you could do:

$ cabal-gild --mode=in-place */*.cabal

That approach feels like the most flexible and also is similar to other source code formatters like Ormolu. It would be a breaking change of course, but it's hard to imagine a solution here that wouldn't be breaking.

tfausak commented 7 months ago

The --io=FILE option I mentioned was added in version 1.1.2.0. I know that doesn't help you original use case, but it should make it easier to modify single files in-place.

turion commented 7 months ago

Awesome, thanks! Will use it!

tfausak commented 6 months ago

For the time being, I don't think I'll change Gild's command line interface. I think formatting multiple package descriptions is a somewhat advanced situation. (Compared to, say, formatting multiple Haskell files.) As such, I think it's reasonable to handle it with a little bit of shell scripting. Or perhaps someone might be interested in writing a little wrapper script that parses a cabal.project file and then calls Gild on all the local packages defined in there.