goreleaser / nfpm

nFPM is Not FPM - a simple deb, rpm, apk, ipk, and arch linux packager written in Go
https://nfpm.goreleaser.com/
MIT License
2.09k stars 154 forks source link

Alternative 'type: tree' behavior to omit intermediate directories? #829

Closed carlosabalde closed 1 week ago

carlosabalde commented 1 month ago

Is your feature request related to a problem? Please describe.

I'm trying to move a project from FPM to nFPM. I like the simplicity of nFPM and I love the 0-dependencies. I think my current workflow is pretty standard: generating a tree structure of all the files and folders to be packaged and then use FPM to package them. Basically, I tell FPM, 'please, create an RPM package with everything in ./build/dist/, and take into account that this and that files are configuration'. Contents of ./build/dist/ could be something like this (beware of the empty folder /var/log/acme/):

├── etc/
│   ├── logrotate.d/
│   │   └── acme
│   └── sysconfig/
│       └── acme
├── lib/
│   └── systemd/
│       └── system/
│           └── acme.service
├── usr/
│   ├── bin/
│   │   └── acme/
│   └── share/
│       ├── doc/
│       │   └── acme/
│       │       ├── CHANGELOG.md
│       │       ├── LICENSE.md
│       │       └── README.md
│       └── man/
│           └── man1/
│               └── acme.1.gz
└── var/
    └── log/
        └── acme/

So, trying to model this using nFPM, I did something like this:

contents:
  # Implementation.
  - src: ./build/dist/lib/
    dst: /lib/
    type: tree
  - src: ./build/dist/usr/
    dst: /usr/
    type: tree
  - src: ./build/dist/var/
    dst: /var/
    type: tree

  # Configuration.
  - src: ./build/dist/etc/logrotate.d/acme
    dst: /etc/logrotate.d/acme
    type: config|noreplace
  - src: ./build/dist/etc/sysconfig/acme
    dst: /etc/sysconfig/acme
    type: config|noreplace

It's not ideal (I'd prefer a single entry to include everything in ./build/dist/, and then list the configuration files separately; somehow that's related to https://github.com/goreleaser/nfpm/discussions/451), but it's good enough. Problem is this doesn't work:

$ yum install ...
Error: Transaction test error:
  file /lib from install of acme1.0.0-1.x86_64 conflicts with file from package filesystem-3.16-2.el9.x86_64
  file /usr/bin from install of acme1.0.0-1.x86_64 conflicts with file from package filesystem-3.16-2.el9.x86_64

In other words, using type: tree to include files is also adding intermediate directories as owned by my package. Explicitly listing all files & empty folders in ./build/dist/ in contents is doable, but it's super error-prone (and also a pain in the ass, even using some templating tool).

Describe the solution you'd like

Since this workflow (i.e. first building the whole file structure to be packaged, and then package it) is pretty common, what do you think about extending type: tree to support an alternative behavior: include all files in there (but not the intermediate folders), same for symlinks, and also include empty folders? That would create a valid package in a simple way. Then, it is up to the user to add type: dir entries for intermediate folders that should be owned by the package (e.g. /usr/share/doc/acme/ in this example). That would create a better package, but IMHO omitting them should be ok too.

Describe alternatives you've considered

A shell script, running some find commands, and then using that input for something like MiniJinja to generate the nFPM configuration. It should work, but it's a lot of complexity.

Search

Code of Conduct

Additional context

No response

caarlos0 commented 3 weeks ago

the alternative tree impl is not something I look forward to implement. As you can see, it is already too complex as is. I regret even adding tree support, tbh.

That said, #834 should fix the problem you reported.

PS: /lib/systemd -> /usr/lib/system, according to the filesystem package on fedora, at least.

carlosabalde commented 3 weeks ago

If you regret adding the tree feature, I understand that something like this might give you the creeps. Yes, #834 will likely serve as a quick workaround for most use cases. I understand that you want to keep the solution simple. It's never easy to find the right balance between simplicity and flexibility. I'll close this issue and learn to love nFPM the way it is :) Thank you for your feedback.