Repository: goreleaser/nfpm
Pull request #267 (2020-12-22 12:10:35)

feat: remove deprecated options
regarding #255, removing the old options.

We will then version this as v2 (breaking change). Easier than keep a lot of things working.

Will still have to do the deprecation notice et all on goreleaser, but its on a single place then.

vercel[bot]: This pull request is being automatically deployed with Vercel ([learn more](https://vercel.link/github-learn-more)).  
To see the status of your deployment, click below or on the icon next to each commit.

🔍 Inspect: [https://vercel.com/goreleaser/nfpm/eamdswce7](https://vercel.com/goreleaser/nfpm/eamdswce7)  
✅ Preview: *Failed*


caarlos0: @djgilcrease I'm not sure why, but symlink tests on rpm and deb are failing 🤔 

I think it wasn't supposed to work before actually, since the actual file is never added to the package... does that makes sense?
djgilcrease: As part of this make sure you read https://blog.golang.org/v2-go-modules many people at my work have tried to bump to v2 but not read that and broken things in odd ways.
caarlos0: > As part of this make sure you read https://blog.golang.org/v2-go-modules many people at my work have tried to bump to v2 but not read that and broken things in odd ways.

yep, here's a picture of me reading it the last time I needed: 

![image](https://user-images.githubusercontent.com/245435/102912580-547b9f80-445c-11eb-8e54-abe8f6207676.png)

😂
caarlos0: > As part of this make sure you read https://blog.golang.org/v2-go-modules many people at my work have tried to bump to v2 but not read that and broken things in odd ways.

In the past, I simply changed the module to `/v2` in `go.mod` (e.g. https://github.com/caarlos0/env), but yeah, they recommend a `v2` subfolder, which I absolutely hate and 0/10 will not do it. Just renaming works for go mod and non-go mod usage, but old versions won't work under go mods anymore (if I recall correctly).

Maybe just keep a v2 branch? Anyone with more experience with that?

caarlos0: > Other strategies may keep major versions on separate branches. However, if v2+ source code is on the repository's default branch (usually master), tools that are not version-aware — including the go command in GOPATH mode — may not distinguish between major versions.

IMHO ¯\_(ツ)_/¯ and we can just append `/v2` to the `go.mod` file... YOLO
codecov[bot]: # [Codecov](https://codecov.io/gh/goreleaser/nfpm/pull/267?src=pr&el=h1) Report
> Merging [#267](https://codecov.io/gh/goreleaser/nfpm/pull/267?src=pr&el=desc) (8d06195) into [master](https://codecov.io/gh/goreleaser/nfpm/commit/df152db001f4bb1ff7de5f39c04416245d09fbf1?el=desc) (df152db) will **decrease** coverage by `0.93%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/goreleaser/nfpm/pull/267/graphs/tree.svg?width=650&height=150&src=pr&token=9QKGIxn7wg)](https://codecov.io/gh/goreleaser/nfpm/pull/267?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #267      +/-   ##
==========================================
- Coverage   70.38%   69.44%   -0.94%     
==========================================
  Files           9        9              
  Lines        1138     1103      -35     
==========================================
- Hits          801      766      -35     
  Misses        209      209              
  Partials      128      128              
```


| [Impacted Files](https://codecov.io/gh/goreleaser/nfpm/pull/267?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [cmd/nfpm/main.go](https://codecov.io/gh/goreleaser/nfpm/pull/267/diff?src=pr&el=tree#diff-Y21kL25mcG0vbWFpbi5nbw==) | `0.00% <ø> (ø)` | |
| [nfpm.go](https://codecov.io/gh/goreleaser/nfpm/pull/267/diff?src=pr&el=tree#diff-bmZwbS5nbw==) | `79.59% <100.00%> (-5.38%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/goreleaser/nfpm/pull/267?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/goreleaser/nfpm/pull/267?src=pr&el=footer). Last update [df152db...8d06195](https://codecov.io/gh/goreleaser/nfpm/pull/267?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

djgilcrease: > > Other strategies may keep major versions on separate branches. However, if v2+ source code is on the repository's default branch (usually master), tools that are not version-aware — including the go command in GOPATH mode — may not distinguish between major versions.
> 
> IMHO ¯_(ツ)_/¯ and we can just append `/v2` to the `go.mod` file... YOLO

Ya that works, I don't really like the branch or sub folder method either, but it does make supporting older versions easier if we need to for some reason.

Patch:
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 4cd0cca..2390c7b 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -42,7 +42,7 @@ jobs:
         name: Set up Go
         uses: actions/setup-go@v2
         with:
-          go-version: 1.14
+          go-version: 1.15
       -
         name: Cache Go modules
         uses: actions/cache@v1
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7899fba..66b840a 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -10,7 +10,7 @@ conduct](/CODE_OF_CONDUCT.md).
 Prerequisites:
 
 * `make`
-* [Go 1.14+](https://golang.org/doc/install)
+* [Go 1.15+](https://golang.org/doc/install)
 
 Clone `nfpm` from source:
 
diff --git a/Makefile b/Makefile
index 17ea961..e81eb56 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@ setup:
 
 
 pull_test_imgs:
-	grep FROM ./acceptance/testdata/*.dockerfile | cut -f2 -d' ' | sort | uniq | while read -r img; do docker pull "$$img"; done
+	grep FROM ./testdata/acceptance/*.dockerfile | cut -f2 -d' ' | sort | uniq | while read -r img; do docker pull "$$img"; done
 .PHONY: pull_test_imgs
 
 acceptance: pull_test_imgs
diff --git a/cmd/nfpm/main.go b/cmd/nfpm/main.go
index 867e1e5..c67bd3a 100644
--- a/cmd/nfpm/main.go
+++ b/cmd/nfpm/main.go
@@ -162,13 +162,17 @@ vendor: "FooBarCorp"
 homepage: "http://example.com"
 license: "MIT"
 changelog: "changelog.yaml"
-files:
-  ./foo: "/usr/local/bin/foo"
-  ./bar: "/usr/local/bin/bar"
-config_files:
-  ./foobar.conf: "/etc/foobar.conf"
-symlinks:
-  /sbin/foo: "/usr/local/bin/foo"
+contents:
+- src: ./foo
+  dst: /usr/local/bin/foo
+- src: ./bar
+  dst: /usr/local/bin/bar
+- src: ./foobar.conf
+  dst: /etc/foobar.conf
+  type: config
+- src: /usr/local/bin/foo
+  dst: /sbin/foo
+  type: symlink
 overrides:
   rpm:
     scripts:
diff --git a/go.mod b/go.mod
index 228edab..64f925a 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
 module github.com/goreleaser/nfpm
 
-go 1.14
+go 1.15
 
 require (
 	github.com/Djarvur/go-err113 v0.1.0 // indirect
@@ -28,6 +28,7 @@ require (
 	github.com/quasilyte/go-ruleguard v0.2.1 // indirect
 	github.com/quasilyte/regex/syntax v0.0.0-20200805063351-8f842688393c // indirect
 	github.com/sassoftware/go-rpmutils v0.0.0-20190420191620-a8f1baeba37b
+	github.com/smartystreets/assertions v1.0.0 // indirect
 	github.com/spf13/afero v1.5.1 // indirect
 	github.com/stretchr/objx v0.3.0 // indirect
 	github.com/stretchr/testify v1.6.1
diff --git a/go.sum b/go.sum
index 30a96b1..f6eb57a 100644
--- a/go.sum
+++ b/go.sum
@@ -452,6 +452,8 @@ github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM
 github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8=
+github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
 github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
 github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
 github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
diff --git a/nfpm.go b/nfpm.go
index 1c17e95..fcf88a9 100644
--- a/nfpm.go
+++ b/nfpm.go
@@ -128,13 +128,16 @@ func (c *Config) Get(format string) (info *Info, err error) {
 		// no overrides
 		return info, nil
 	}
-	if !override.hasResetFiles {
-		override.resetFiles(format)
-		c.Contents = append(c.Contents, override.Contents...)
-	}
 	if err = mergo.Merge(&info.Overridables, override, mergo.WithOverride); err != nil {
 		return nil, fmt.Errorf("failed to merge overrides into info: %w", err)
 	}
+	var contents []*files.Content
+	for _, f := range info.Contents {
+		if f.Packager == format || f.Packager == "" {
+			contents = append(contents, f)
+		}
+	}
+	info.Contents = contents
 	return info, nil
 }
 
@@ -176,7 +179,6 @@ type Info struct {
 }
 
 func (i *Info) Validate() error {
-	i.resetFiles("")
 	return Validate(i)
 }
 
@@ -201,84 +203,26 @@ func (i *Info) GetChangeLog() (log *chglog.PackageChangeLog, err error) {
 
 // Overridables contain the field which are overridable in a package.
 type Overridables struct {
-	Replaces      []string          `yaml:"replaces,omitempty"`
-	Provides      []string          `yaml:"provides,omitempty"`
-	Depends       []string          `yaml:"depends,omitempty"`
-	Recommends    []string          `yaml:"recommends,omitempty"`
-	Suggests      []string          `yaml:"suggests,omitempty"`
-	Conflicts     []string          `yaml:"conflicts,omitempty"`
-	Contents      files.Contents    `yaml:"contents,omitempty"`
-	Files         map[string]string `yaml:"files,omitempty"`
-	ConfigFiles   map[string]string `yaml:"config_files,omitempty"`
-	Symlinks      map[string]string `yaml:"symlinks,omitempty"`
-	EmptyFolders  []string          `yaml:"empty_folders,omitempty"`
-	Scripts       Scripts           `yaml:"scripts,omitempty"`
-	RPM           RPM               `yaml:"rpm,omitempty"`
-	Deb           Deb               `yaml:"deb,omitempty"`
-	APK           APK               `yaml:"apk,omitempty"`
-	hasResetFiles bool
-}
-
-func (o *Overridables) resetFiles(packager string) {
-	if o.hasResetFiles {
-		return
-	}
-	for src, dst := range o.Files {
-		o.Contents = append(o.Contents, &files.Content{
-			Source:      src,
-			Destination: dst,
-			Packager:    packager,
-		})
-	}
-	o.Files = nil
-	for src, dst := range o.ConfigFiles {
-		o.Contents = append(o.Contents, &files.Content{
-			Source:      src,
-			Destination: dst,
-			Type:        "config",
-			Packager:    packager,
-		})
-	}
-	o.ConfigFiles = nil
-
-	// Symlinks is backwards from other in the config file
-	for dst, src := range o.Symlinks {
-		o.Contents = append(o.Contents, &files.Content{
-			Source:      src,
-			Destination: dst,
-			Type:        "symlink",
-			Packager:    packager,
-		})
-	}
-	o.Symlinks = nil
-	for src, dst := range o.RPM.ConfigNoReplaceFiles {
-		o.Contents = append(o.Contents, &files.Content{
-			Source:      src,
-			Destination: dst,
-			Type:        "config|noreplace",
-			Packager:    "rpm",
-		})
-	}
-	o.RPM.ConfigNoReplaceFiles = nil
-	for _, dst := range o.RPM.GhostFiles {
-		o.Contents = append(o.Contents, &files.Content{
-			Destination: dst,
-			Type:        "ghost",
-			Packager:    "rpm",
-		})
-	}
-	o.hasResetFiles = true
+	Replaces     []string       `yaml:"replaces,omitempty"`
+	Provides     []string       `yaml:"provides,omitempty"`
+	Depends      []string       `yaml:"depends,omitempty"`
+	Recommends   []string       `yaml:"recommends,omitempty"`
+	Suggests     []string       `yaml:"suggests,omitempty"`
+	Conflicts    []string       `yaml:"conflicts,omitempty"`
+	Contents     files.Contents `yaml:"contents,omitempty"`
+	EmptyFolders []string       `yaml:"empty_folders,omitempty"`
+	Scripts      Scripts        `yaml:"scripts,omitempty"`
+	RPM          RPM            `yaml:"rpm,omitempty"`
+	Deb          Deb            `yaml:"deb,omitempty"`
+	APK          APK            `yaml:"apk,omitempty"`
 }
 
 // RPM is custom configs that are only available on RPM packages.
 type RPM struct {
-	Group       string `yaml:"group,omitempty"`
-	Summary     string `yaml:"summary,omitempty"`
-	Compression string `yaml:"compression,omitempty"`
-	// https://www.cl.cam.ac.uk/~jw35/docs/rpm_config.html
-	ConfigNoReplaceFiles map[string]string `yaml:"config_noreplace_files,omitempty"`
-	Signature            RPMSignature      `yaml:"signature,omitempty"`
-	GhostFiles           []string          `yaml:"ghost_files,omitempty"`
+	Group       string       `yaml:"group,omitempty"`
+	Summary     string       `yaml:"summary,omitempty"`
+	Compression string       `yaml:"compression,omitempty"`
+	Signature   RPMSignature `yaml:"signature,omitempty"`
 }
 
 type RPMSignature struct {


Test patch:
diff --git a/acceptance_test.go b/acceptance_test.go
index 3f1a7ea..3ce0aa5 100644
--- a/acceptance_test.go
+++ b/acceptance_test.go
@@ -100,7 +100,7 @@ func TestConfigNoReplace(t *testing.T) {
 	info.Target = target
 	require.NoError(t, pkg.Package(nfpm.WithDefaults(info), f))
 
-	t.Run("noreplace-rpm", func(t *testing.T) {
+	t.Run("rpm", func(t *testing.T) {
 		accept(t, acceptParms{
 			Name:       "noreplace_rpm",
 			Conf:       "config-noreplace.yaml",
diff --git a/apk/apk_test.go b/apk/apk_test.go
index 0f12b5a..6216085 100644
--- a/apk/apk_test.go
+++ b/apk/apk_test.go
@@ -17,6 +17,7 @@ import (
 	"github.com/stretchr/testify/require"
 
 	"github.com/goreleaser/nfpm"
+	"github.com/goreleaser/nfpm/files"
 	"github.com/goreleaser/nfpm/internal/sign"
 )
 
@@ -60,12 +61,20 @@ func exampleInfo() *nfpm.Info {
 				"zsh",
 				"foobarsh",
 			},
-			Files: map[string]string{
-				"../testdata/fake":          "/usr/local/bin/fake",
-				"../testdata/whatever.conf": "/usr/share/doc/fake/fake.txt",
-			},
-			ConfigFiles: map[string]string{
-				"../testdata/whatever.conf": "/etc/fake/fake.conf",
+			Contents: []*files.Content{
+				{
+					Source:      "../testdata/fake",
+					Destination: "/usr/local/bin/fake",
+				},
+				{
+					Source:      "../testdata/whatever.conf",
+					Destination: "/usr/share/doc/fake/fake.txt",
+				},
+				{
+					Source:      "../testdata/whatever.conf",
+					Destination: "/etc/fake/fake.conf",
+					Type:        "config",
+				},
 			},
 			EmptyFolders: []string{
 				"/var/log/whatever",
@@ -169,11 +178,16 @@ func TestFileDoesNotExist(t *testing.T) {
 				Depends: []string{
 					"bash",
 				},
-				Files: map[string]string{
-					"../testdata/fake": "/usr/local/bin/fake",
-				},
-				ConfigFiles: map[string]string{
-					"../testdata/whatever.confzzz": "/etc/fake/fake.conf",
+				Contents: []*files.Content{
+					{
+						Source:      "../testdata/fake",
+						Destination: "/usr/local/bin/fake",
+					},
+					{
+						Source:      "../testdata/whatever.confzzz",
+						Destination: "/etc/fake/fake.conf",
+						Type:        "config",
+					},
 				},
 			},
 		}),
@@ -320,8 +334,11 @@ func TestSignatureError(t *testing.T) {
 func TestDisableGlobbing(t *testing.T) {
 	info := exampleInfo()
 	info.DisableGlobbing = true
-	info.Files = map[string]string{
-		"../testdata/{file}[": "/test/{file}[",
+	info.Contents = []*files.Content{
+		{
+			Source:      "../testdata/{file}[",
+			Destination: "/test/{file}[",
+		},
 	}
 	err := info.Validate()
 	require.NoError(t, err)
@@ -404,9 +421,12 @@ func TestAPKConventionalFileName(t *testing.T) {
 
 func TestPackageSymlinks(t *testing.T) {
 	info := exampleInfo()
-	info.Files = map[string]string{}
-	info.Symlinks = map[string]string{
-		"../testdata/fake": "fake",
+	info.Contents = []*files.Content{
+		{
+			Source:      "../testdata/fake",
+			Destination: "fake",
+			Type:        "symlink",
+		},
 	}
 	assert.NoError(t, Default.Package(info, ioutil.Discard))
 }
diff --git a/deb/deb_test.go b/deb/deb_test.go
index 7ce7575..5ec0ea3 100644
--- a/deb/deb_test.go
+++ b/deb/deb_test.go
@@ -61,12 +61,20 @@ func exampleInfo() *nfpm.Info {
 			Conflicts: []string{
 				"zsh",
 			},
-			Files: map[string]string{
-				"../testdata/fake":          "/usr/local/bin/fake",
-				"../testdata/whatever.conf": "/usr/share/doc/fake/fake.txt",
-			},
-			ConfigFiles: map[string]string{
-				"../testdata/whatever.conf": "/etc/fake/fake.conf",
+			Contents: []*files.Content{
+				{
+					Source:      "../testdata/fake",
+					Destination: "/usr/local/bin/fake",
+				},
+				{
+					Source:      "../testdata/whatever.conf",
+					Destination: "/usr/share/doc/fake/fake.txt",
+				},
+				{
+					Source:      "../testdata/whatever.conf",
+					Destination: "/etc/fake/fake.conf",
+					Type:        "config",
+				},
 			},
 			EmptyFolders: []string{
 				"/var/log/whatever",
@@ -230,14 +238,13 @@ func TestNoJoinsControl(t *testing.T) {
 			Homepage:    "http://carlosbecker.com",
 			Vendor:      "nope",
 			Overridables: nfpm.Overridables{
-				Depends:     []string{},
-				Recommends:  []string{},
-				Suggests:    []string{},
-				Replaces:    []string{},
-				Provides:    []string{},
-				Conflicts:   []string{},
-				Files:       map[string]string{},
-				ConfigFiles: map[string]string{},
+				Depends:    []string{},
+				Recommends: []string{},
+				Suggests:   []string{},
+				Replaces:   []string{},
+				Provides:   []string{},
+				Conflicts:  []string{},
+				Contents:   []*files.Content{},
 			},
 		}),
 		InstalledSize: 10,
@@ -267,11 +274,16 @@ func TestDebFileDoesNotExist(t *testing.T) {
 				Depends: []string{
 					"bash",
 				},
-				Files: map[string]string{
-					"../testdata/fake": "/usr/local/bin/fake",
-				},
-				ConfigFiles: map[string]string{
-					"../testdata/whatever.confzzz": "/etc/fake/fake.conf",
+				Contents: []*files.Content{
+					{
+						Source:      "../testdata/fake",
+						Destination: "/usr/local/bin/fake",
+					},
+					{
+						Source:      "../testdata/whatever.confzzz",
+						Destination: "/etc/fake/fake.conf",
+						Type:        "config",
+					},
 				},
 			},
 		}),
@@ -317,8 +329,12 @@ func TestConffiles(t *testing.T) {
 		Version:     "1.0.0",
 		Section:     "default",
 		Overridables: nfpm.Overridables{
-			ConfigFiles: map[string]string{
-				"../testdata/fake": "/etc/fake",
+			Contents: []*files.Content{
+				{
+					Source:      "../testdata/fake",
+					Destination: "/etc/fake",
+					Type:        "config",
+				},
 			},
 		},
 	})
@@ -636,8 +652,11 @@ func TestSymlinkInFiles(t *testing.T) {
 		Description: "This package's config references a file via symlink.",
 		Version:     "1.0.0",
 		Overridables: nfpm.Overridables{
-			Files: map[string]string{
-				symlinkTo(t, symlinkTarget): packagedTarget,
+			Contents: []*files.Content{
+				{
+					Source:      symlinkTo(t, symlinkTarget),
+					Destination: packagedTarget,
+				},
 			},
 		},
 	}
@@ -669,11 +688,16 @@ func TestSymlink(t *testing.T) {
 		Description: "This package's config references a file via symlink.",
 		Version:     "1.0.0",
 		Overridables: nfpm.Overridables{
-			Files: map[string]string{
-				"../testdata/whatever.conf": configFilePath,
-			},
-			Symlinks: map[string]string{
-				symlink: symlinkTarget,
+			Contents: []*files.Content{
+				{
+					Source:      "../testdata/whatever.conf",
+					Destination: configFilePath,
+				},
+				{
+					Source:      symlinkTarget,
+					Destination: symlink,
+					Type:        "symlink",
+				},
 			},
 		},
 	}
@@ -693,8 +717,12 @@ func TestSymlink(t *testing.T) {
 
 func TestEnsureRelativePrefixInTarGzFiles(t *testing.T) {
 	info := exampleInfo()
-	info.Symlinks = map[string]string{
-		"/symlink/to/fake.txt": "/usr/share/doc/fake/fake.txt",
+	info.Contents = []*files.Content{
+		{
+			Source:      "/symlink/to/fake.txt",
+			Destination: "/usr/share/doc/fake/fake.txt",
+			Type:        "symlink",
+		},
 	}
 	info.Changelog = "../testdata/changelog.yaml"
 	err := info.Validate()
@@ -809,11 +837,13 @@ func TestDebsigsSignatureError(t *testing.T) {
 func TestDisableGlobbing(t *testing.T) {
 	info := exampleInfo()
 	info.DisableGlobbing = true
-	info.Files = map[string]string{
-		"../testdata/{file}[": "/test/{file}[",
+	info.Contents = []*files.Content{
+		{
+			Source:      "../testdata/{file}[",
+			Destination: "/test/{file}[",
+		},
 	}
-	err := info.Validate()
-	require.NoError(t, err)
+	require.NoError(t, info.Validate())
 
 	dataTarGz, _, _, err := createDataTarGz(info)
 	require.NoError(t, err)
@@ -928,18 +958,10 @@ func symlinkTo(tb testing.TB, fileName string) string {
 	target, err := filepath.Abs(fileName)
 	assert.NoError(tb, err)
 
-	tempDir, err := ioutil.TempDir("", "nfpm_deb_test")
-	assert.NoError(tb, err)
-
-	symlinkName := filepath.Join(tempDir, "symlink")
+	symlinkName := filepath.Join(tb.TempDir(), "symlink")
 	err = os.Symlink(target, symlinkName)
 	assert.NoError(tb, err)
 
-	tb.Cleanup(func() {
-		err = os.RemoveAll(tempDir)
-		assert.NoError(tb, err)
-	})
-
 	return files.ToNixPath(symlinkName)
 }
 
diff --git a/nfpm_test.go b/nfpm_test.go
index 7447dd0..768701b 100644
--- a/nfpm_test.go
+++ b/nfpm_test.go
@@ -8,10 +8,10 @@ import (
 	"strings"
 	"testing"
 
-	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 
 	"github.com/goreleaser/nfpm"
+	"github.com/goreleaser/nfpm/files"
 )
 
 func TestRegister(t *testing.T) {
@@ -20,20 +20,20 @@ func TestRegister(t *testing.T) {
 	nfpm.RegisterPackager(format, pkgr)
 	got, err := nfpm.Get(format)
 	require.NoError(t, err)
-	assert.Equal(t, pkgr, got)
+	require.Equal(t, pkgr, got)
 }
 
 func TestGet(t *testing.T) {
 	format := "TestGet"
 	got, err := nfpm.Get(format)
 	require.Error(t, err)
-	assert.EqualError(t, err, "no packager registered for the format "+format)
-	assert.Nil(t, got)
+	require.EqualError(t, err, "no packager registered for the format "+format)
+	require.Nil(t, got)
 	pkgr := &fakePackager{}
 	nfpm.RegisterPackager(format, pkgr)
 	got, err = nfpm.Get(format)
 	require.NoError(t, err)
-	assert.Equal(t, pkgr, got)
+	require.Equal(t, pkgr, got)
 }
 
 func TestDefaultsVersion(t *testing.T) {
@@ -41,26 +41,26 @@ func TestDefaultsVersion(t *testing.T) {
 		Version: "v1.0.0",
 	}
 	info = nfpm.WithDefaults(info)
-	assert.NotEmpty(t, info.Platform)
-	assert.Equal(t, "1.0.0", info.Version)
-	assert.Equal(t, "", info.Release)
-	assert.Equal(t, "", info.Prerelease)
+	require.NotEmpty(t, info.Platform)
+	require.Equal(t, "1.0.0", info.Version)
+	require.Equal(t, "", info.Release)
+	require.Equal(t, "", info.Prerelease)
 
 	info = &nfpm.Info{
 		Version: "v1.0.0-rc1",
 	}
 	info = nfpm.WithDefaults(info)
-	assert.Equal(t, "1.0.0", info.Version)
-	assert.Equal(t, "", info.Release)
-	assert.Equal(t, "rc1", info.Prerelease)
+	require.Equal(t, "1.0.0", info.Version)
+	require.Equal(t, "", info.Release)
+	require.Equal(t, "rc1", info.Prerelease)
 
 	info = &nfpm.Info{
 		Version: "v1.0.0-beta1",
 	}
 	info = nfpm.WithDefaults(info)
-	assert.Equal(t, "1.0.0", info.Version)
-	assert.Equal(t, "", info.Release)
-	assert.Equal(t, "beta1", info.Prerelease)
+	require.Equal(t, "1.0.0", info.Version)
+	require.Equal(t, "", info.Release)
+	require.Equal(t, "beta1", info.Prerelease)
 
 	info = &nfpm.Info{
 		Version:    "v1.0.0-1",
@@ -68,9 +68,9 @@ func TestDefaultsVersion(t *testing.T) {
 		Prerelease: "beta1",
 	}
 	info = nfpm.WithDefaults(info)
-	assert.Equal(t, "1.0.0", info.Version)
-	assert.Equal(t, "2", info.Release)
-	assert.Equal(t, "beta1", info.Prerelease)
+	require.Equal(t, "1.0.0", info.Version)
+	require.Equal(t, "2", info.Release)
+	require.Equal(t, "beta1", info.Prerelease)
 
 	info = &nfpm.Info{
 		Version:    "v1.0.0-1+xdg2",
@@ -78,10 +78,10 @@ func TestDefaultsVersion(t *testing.T) {
 		Prerelease: "beta1",
 	}
 	info = nfpm.WithDefaults(info)
-	assert.Equal(t, "1.0.0", info.Version)
-	assert.Equal(t, "2", info.Release)
-	assert.Equal(t, "beta1", info.Prerelease)
-	assert.Equal(t, "", info.Deb.VersionMetadata)
+	require.Equal(t, "1.0.0", info.Version)
+	require.Equal(t, "2", info.Release)
+	require.Equal(t, "beta1", info.Prerelease)
+	require.Equal(t, "", info.Deb.VersionMetadata)
 }
 
 func TestDefaults(t *testing.T) {
@@ -91,7 +91,7 @@ func TestDefaults(t *testing.T) {
 		Description: "no description given",
 	}
 	got := nfpm.WithDefaults(info)
-	assert.Equal(t, info, got)
+	require.Equal(t, info, got)
 }
 
 func TestValidate(t *testing.T) {
@@ -100,8 +100,11 @@ func TestValidate(t *testing.T) {
 		Arch:    "asd",
 		Version: "1.2.3",
 		Overridables: nfpm.Overridables{
-			Files: map[string]string{
-				"asa": "asd",
+			Contents: []*files.Content{
+				{
+					Source:      "./testdata/contents.yaml",
+					Destination: "asd",
+				},
 			},
 		},
 	}))
@@ -110,8 +113,12 @@ func TestValidate(t *testing.T) {
 		Arch:    "asd",
 		Version: "1.2.3",
 		Overridables: nfpm.Overridables{
-			ConfigFiles: map[string]string{
-				"asa": "asd",
+			Contents: []*files.Content{
+				{
+					Source:      "./testdata/contents.yaml",
+					Destination: "asd",
+					Type:        "config",
+				},
 			},
 		},
 	}))
@@ -149,13 +156,13 @@ func TestParseFile(t *testing.T) {
 	require.Error(t, err)
 	config, err := nfpm.ParseFile("./testdata/versionenv.yaml")
 	require.NoError(t, err)
-	assert.Equal(t, fmt.Sprintf("v%s", os.Getenv("GOROOT")), config.Version)
+	require.Equal(t, fmt.Sprintf("v%s", os.Getenv("GOROOT")), config.Version)
 }
 
 func TestParseEnhancedFile(t *testing.T) {
 	config, err := nfpm.ParseFile("./testdata/contents.yaml")
 	require.NoError(t, err)
-	assert.Equal(t, config.Name, "contents foo")
+	require.Equal(t, config.Name, "contents foo")
 	shouldFind := 5
 	if len(config.Contents) != shouldFind {
 		t.Errorf("should have had %d files but found %d", shouldFind, len(config.Contents))
@@ -192,7 +199,7 @@ func TestOptionsFromEnvironment(t *testing.T) {
 		os.Setenv("VERSION", version)
 		info, err := nfpm.Parse(strings.NewReader("name: foo\nversion: $VERSION"))
 		require.NoError(t, err)
-		assert.Equal(t, version, info.Version)
+		require.Equal(t, version, info.Version)
 	})
 
 	t.Run("release", func(t *testing.T) {
@@ -200,7 +207,7 @@ func TestOptionsFromEnvironment(t *testing.T) {
 		os.Setenv("RELEASE", release)
 		info, err := nfpm.Parse(strings.NewReader("name: foo\nrelease: $RELEASE"))
 		require.NoError(t, err)
-		assert.Equal(t, release, info.Release)
+		require.Equal(t, release, info.Release)
 	})
 
 	t.Run("global passphrase", func(t *testing.T) {
@@ -208,9 +215,9 @@ func TestOptionsFromEnvironment(t *testing.T) {
 		os.Setenv("NFPM_PASSPHRASE", globalPass)
 		info, err := nfpm.Parse(strings.NewReader("name: foo"))
 		require.NoError(t, err)
-		assert.Equal(t, globalPass, info.Deb.Signature.KeyPassphrase)
-		assert.Equal(t, globalPass, info.RPM.Signature.KeyPassphrase)
-		assert.Equal(t, globalPass, info.APK.Signature.KeyPassphrase)
+		require.Equal(t, globalPass, info.Deb.Signature.KeyPassphrase)
+		require.Equal(t, globalPass, info.RPM.Signature.KeyPassphrase)
+		require.Equal(t, globalPass, info.APK.Signature.KeyPassphrase)
 	})
 
 	t.Run("specific passphrases", func(t *testing.T) {
@@ -221,59 +228,48 @@ func TestOptionsFromEnvironment(t *testing.T) {
 		os.Setenv("NFPM_APK_PASSPHRASE", apkPass)
 		info, err := nfpm.Parse(strings.NewReader("name: foo"))
 		require.NoError(t, err)
-		assert.Equal(t, debPass, info.Deb.Signature.KeyPassphrase)
-		assert.Equal(t, rpmPass, info.RPM.Signature.KeyPassphrase)
-		assert.Equal(t, apkPass, info.APK.Signature.KeyPassphrase)
+		require.Equal(t, debPass, info.Deb.Signature.KeyPassphrase)
+		require.Equal(t, rpmPass, info.RPM.Signature.KeyPassphrase)
+		require.Equal(t, apkPass, info.APK.Signature.KeyPassphrase)
 	})
 }
 
 func TestOverrides(t *testing.T) {
+	nfpm.RegisterPackager("deb", &fakePackager{})
+	nfpm.RegisterPackager("rpm", &fakePackager{})
+	nfpm.RegisterPackager("apk", &fakePackager{})
+
 	file := "./testdata/overrides.yaml"
 	config, err := nfpm.ParseFile(file)
 	require.NoError(t, err)
-	assert.Equal(t, "foo", config.Name)
-	assert.Equal(t, "amd64", config.Arch)
-
-	// deb overrides
-	deb, err := config.Get("deb")
-	require.NoError(t, err)
-	assert.Contains(t, deb.Depends, "deb_depend")
-	assert.NotContains(t, deb.Depends, "rpm_depend")
-	for _, f := range deb.Contents {
-		fmt.Printf("%+#v\n", f)
-		assert.True(t, f.Packager != "rpm")
-		assert.True(t, f.Packager != "apk")
-		if f.Packager == "deb" {
-			assert.Contains(t, f.Destination, "/deb")
-		}
-		if f.Packager == "" {
-			assert.True(t, f.Destination == "/etc/foo/whatever.conf")
-		}
-	}
-	assert.Equal(t, "amd64", deb.Arch)
+	require.Equal(t, "foo", config.Name)
+	require.Equal(t, "amd64", config.Arch)
 
-	// rpm overrides
-	rpm, err := config.Get("rpm")
-	require.NoError(t, err)
-	assert.Contains(t, rpm.Depends, "rpm_depend")
-	assert.NotContains(t, rpm.Depends, "deb_depend")
-	for _, f := range rpm.Contents {
-		fmt.Printf("%+#v\n", f)
-		assert.True(t, f.Packager != "deb")
-		assert.True(t, f.Packager != "apk")
-		if f.Packager == "rpm" {
-			assert.Contains(t, f.Destination, "/rpm")
-		}
-		if f.Packager == "" {
-			assert.True(t, f.Destination == "/etc/foo/whatever.conf")
-		}
+	for _, format := range []string{"apk", "deb", "rpm"} {
+		format := format
+		t.Run(format, func(t *testing.T) {
+			pkg, err := config.Get(format)
+			require.NoError(t, err)
+			require.Equal(t, pkg.Depends, []string{format + "_depend"})
+			for _, f := range pkg.Contents {
+				switch f.Packager {
+				case format:
+					require.Contains(t, f.Destination, "/"+format)
+				case "":
+					require.True(t, f.Destination == "/etc/foo/whatever.conf")
+				default:
+					t.Fatalf("invalid packager: %s", f.Packager)
+				}
+			}
+			require.Equal(t, "amd64", pkg.Arch)
+		})
 	}
-	assert.Equal(t, "amd64", rpm.Arch)
 
-	// no overrides
-	info, err := config.Get("doesnotexist")
-	require.NoError(t, err)
-	assert.True(t, reflect.DeepEqual(&config.Info, info))
+	t.Run("no_overrides", func(t *testing.T) {
+		info, err := config.Get("doesnotexist")
+		require.NoError(t, err)
+		require.True(t, reflect.DeepEqual(&config.Info, info))
+	})
 }
 
 type fakePackager struct{}
diff --git a/rpm/rpm_test.go b/rpm/rpm_test.go
index 7915b8f..9676ea3 100644
--- a/rpm/rpm_test.go
+++ b/rpm/rpm_test.go
@@ -55,11 +55,16 @@ func exampleInfo() *nfpm.Info {
 			Conflicts: []string{
 				"zsh",
 			},
-			Files: map[string]string{
-				"../testdata/fake": "/usr/local/bin/fake",
-			},
-			ConfigFiles: map[string]string{
-				"../testdata/whatever.conf": "/etc/fake/fake.conf",
+			Contents: []*files.Content{
+				{
+					Source:      "../testdata/fake",
+					Destination: "/usr/local/bin/fake",
+				},
+				{
+					Source:      "../testdata/whatever.conf",
+					Destination: "/etc/fake/fake.conf",
+					Type:        "config",
+				},
 			},
 			EmptyFolders: []string{
 				"/var/log/whatever",
@@ -365,11 +370,16 @@ echo "Postremove" > /dev/null
 
 func TestRPMFileDoesNotExist(t *testing.T) {
 	info := exampleInfo()
-	info.Files = map[string]string{
-		"../testdata/fake": "/usr/local/bin/fake",
-	}
-	info.ConfigFiles = map[string]string{
-		"../testdata/whatever.confzzz": "/etc/fake/fake.conf",
+	info.Contents = []*files.Content{
+		{
+			Source:      "../testdata/fake",
+			Destination: "/usr/local/bin/fake",
+		},
+		{
+			Source:      "../testdata/whatever.confzzz",
+			Destination: "/etc/fake/fake.conf",
+			Type:        "config",
+		},
 	}
 	var err = Default.Package(info, ioutil.Discard)
 	assert.EqualError(t, err, "matching \"../testdata/whatever.confzzz\": file does not exist")
@@ -397,9 +407,11 @@ func TestConfigNoReplace(t *testing.T) {
 		Description: "This package's config references a file via symlink.",
 		Version:     "1.0.0",
 		Overridables: nfpm.Overridables{
-			RPM: nfpm.RPM{
-				ConfigNoReplaceFiles: map[string]string{
-					buildConfigFile: packageConfigFile,
+			Contents: []*files.Content{
+				{
+					Source:      buildConfigFile,
+					Destination: packageConfigFile,
+					Type:        "config|noreplace",
 				},
 			},
 		},
@@ -533,8 +545,11 @@ func TestSymlinkInFiles(t *testing.T) {
 		Description: "This package's config references a file via symlink.",
 		Version:     "1.0.0",
 		Overridables: nfpm.Overridables{
-			Files: map[string]string{
-				symlinkTo(t, symlinkTarget): packagedTarget,
+			Contents: []*files.Content{
+				{
+					Source:      symlinkTo(t, symlinkTarget),
+					Destination: packagedTarget,
+				},
 			},
 		},
 	}
@@ -565,11 +580,16 @@ func TestSymlink(t *testing.T) {
 		Description: "This package's config references a file via symlink.",
 		Version:     "1.0.0",
 		Overridables: nfpm.Overridables{
-			Files: map[string]string{
-				"../testdata/whatever.conf": configFilePath,
-			},
-			Symlinks: map[string]string{
-				symlink: symlinkTarget,
+			Contents: []*files.Content{
+				{
+					Source:      "../testdata/whatever.conf",
+					Destination: configFilePath,
+				},
+				{
+					Source:      symlinkTarget,
+					Destination: symlink,
+					Type:        "symlink",
+				},
 			},
 		},
 	}
@@ -628,11 +648,18 @@ func TestRPMGhostFiles(t *testing.T) {
 	)
 
 	info := &nfpm.Info{
-		Name:         "rpm-ghost",
-		Arch:         "amd64",
-		Description:  "This RPM contains ghost files.",
-		Version:      "1.0.0",
-		Overridables: nfpm.Overridables{RPM: nfpm.RPM{GhostFiles: []string{filename}}},
+		Name:        "rpm-ghost",
+		Arch:        "amd64",
+		Description: "This RPM contains ghost files.",
+		Version:     "1.0.0",
+		Overridables: nfpm.Overridables{
+			Contents: []*files.Content{
+				{
+					Destination: filename,
+					Type:        "ghost",
+				},
+			},
+		},
 	}
 
 	var rpmFileBuffer bytes.Buffer
@@ -666,8 +693,11 @@ func TestRPMGhostFiles(t *testing.T) {
 func TestDisableGlobbing(t *testing.T) {
 	info := exampleInfo()
 	info.DisableGlobbing = true
-	info.Files = map[string]string{
-		"../testdata/{file}[": "/test/{file}[",
+	info.Contents = []*files.Content{
+		{
+			Source:      "../testdata/{file}[",
+			Destination: "/test/{file}[",
+		},
 	}
 
 	var rpmFileBuffer bytes.Buffer
@@ -760,17 +790,9 @@ func symlinkTo(tb testing.TB, fileName string) string {
 	target, err := filepath.Abs(fileName)
 	assert.NoError(tb, err)
 
-	tempDir, err := ioutil.TempDir("", "nfpm_rpm_test")
-	assert.NoError(tb, err)
-
-	symlinkName := path.Join(tempDir, "symlink")
+	symlinkName := path.Join(tb.TempDir(), "symlink")
 	err = os.Symlink(target, symlinkName)
 	assert.NoError(tb, err)
 
-	tb.Cleanup(func() {
-		err = os.RemoveAll(tempDir)
-		assert.NoError(tb, err)
-	})
-
 	return files.ToNixPath(symlinkName)
 }
diff --git a/testdata/acceptance/complex.386.yaml b/testdata/acceptance/complex.386.yaml
index d8946b4..2622700 100644
--- a/testdata/acceptance/complex.386.yaml
+++ b/testdata/acceptance/complex.386.yaml
@@ -17,11 +17,14 @@ description: |
 vendor: "foobar"
 homepage: "https://foobar.org"
 license: "MIT"
-files:
-  ./testdata/fake: "/usr/local/bin/fake"
-  ./testdata/acceptance/folder/*: "/usr/share/whatever/folder/"
-config_files:
-  ./testdata/whatever.conf: "/etc/foo/whatever.conf"
+contents:
+- src: ./testdata/fake
+  dst: /usr/local/bin/fake
+- src: ./testdata/acceptance/folder/*
+  dst: /usr/share/whatever/folder/
+- src: ./testdata/whatever.conf
+  dst: /etc/foo/whatever.conf
+  type: config
 empty_folders:
 - /var/log/whatever
 - /usr/share/foo
diff --git a/testdata/acceptance/complex.yaml b/testdata/acceptance/complex.yaml
index 6aed570..12b7389 100644
--- a/testdata/acceptance/complex.yaml
+++ b/testdata/acceptance/complex.yaml
@@ -19,11 +19,14 @@ description: |
 vendor: "foobar"
 homepage: "https://foobar.org"
 license: "MIT"
-files:
-  ./testdata/fake: "/usr/local/bin/fake"
-  ./testdata/acceptance/folder/*: "/usr/share/whatever/folder/"
-config_files:
-  ./testdata/whatever.conf: "/etc/foo/whatever.conf"
+contents:
+- src: ./testdata/fake
+  dst: /usr/local/bin/fake
+- src: ./testdata/acceptance/folder/*
+  dst: /usr/share/whatever/folder/
+- src: ./testdata/whatever.conf
+  dst: /etc/foo/whatever.conf
+  type: config
 empty_folders:
 - /var/log/whatever
 - /usr/share/foo
diff --git a/testdata/acceptance/config-noreplace-old.yaml b/testdata/acceptance/config-noreplace-old.yaml
index 6773597..31aaf25 100644
--- a/testdata/acceptance/config-noreplace-old.yaml
+++ b/testdata/acceptance/config-noreplace-old.yaml
@@ -6,8 +6,10 @@ maintainer: "Foo Bar"
 vendor: "foobar"
 homepage: "https://foobar.org"
 license: "MIT"
-config_files:
-  ./testdata/whatever.conf: "/etc/regular.conf"
-rpm:
-  config_noreplace_files:
-    ./testdata/whatever.conf: "/etc/noreplace.conf"
+contents:
+- src: ./testdata/whatever.conf
+  dst: /etc/regular.conf
+  type: config
+- src: ./testdata/whatever.conf
+  dst: /etc/noreplace.conf
+  type: config|noreplace
diff --git a/testdata/acceptance/config-noreplace.yaml b/testdata/acceptance/config-noreplace.yaml
index ae5fe93..df21c8c 100644
--- a/testdata/acceptance/config-noreplace.yaml
+++ b/testdata/acceptance/config-noreplace.yaml
@@ -6,8 +6,10 @@ maintainer: "Foo Bar"
 vendor: "foobar"
 homepage: "https://foobar.org"
 license: "MIT"
-config_files:
-  ./testdata/whatever2.conf: "/etc/regular.conf"
-rpm:
-  config_noreplace_files:
-    ./testdata/whatever2.conf: "/etc/noreplace.conf"
+contents:
+- src: ./testdata/whatever2.conf
+  dst: /etc/regular.conf
+  type: config
+- src: ./testdata/whatever2.conf
+  dst: /etc/noreplace.conf
+  type: config|noreplace
diff --git a/testdata/acceptance/env-var-version.yaml b/testdata/acceptance/env-var-version.yaml
index 73b4ba7..ef0d5af 100644
--- a/testdata/acceptance/env-var-version.yaml
+++ b/testdata/acceptance/env-var-version.yaml
@@ -17,11 +17,14 @@ description: |
 vendor: "foobar"
 homepage: "https://foobar.org"
 license: "MIT"
-files:
-  ./testdata/fake: "/usr/local/bin/fake"
-  ./testdata/acceptance/folder/**/*: "/usr/share/whatever/folder/"
-config_files:
-  ./testdata/whatever.conf: "/etc/foo/whatever.conf"
+contents:
+- src: ./testdata/fake
+  dst: /usr/local/bin/fake
+- src: ./testdata/acceptance/folder/**/*
+  dst: /usr/share/whatever/folder/
+- src: ./testdata/whatever.conf
+  dst: /etc/foo/whatever.conf
+  type: config
 empty_folders:
   - /var/log/whatever
   - /usr/share/foo
diff --git a/testdata/acceptance/gzip.compression.yaml b/testdata/acceptance/gzip.compression.yaml
index a36dbb4..a18129b 100644
--- a/testdata/acceptance/gzip.compression.yaml
+++ b/testdata/acceptance/gzip.compression.yaml
@@ -9,9 +9,11 @@ description: |
 vendor: "foobar"
 homepage: "https://foobar.org"
 license: "MIT"
-files:
-  ./testdata/fake: "/usr/local/bin/fake"
-config_files:
-  ./testdata/whatever.conf: "/etc/foo/whatever.conf"
+contents:
+- src: ./testdata/fake
+  dst: /usr/local/bin/fake
+- src: ./testdata/whatever.conf
+  dst: /etc/foo/whatever.conf
+  type: config
 rpm:
-  compression: "gzip"
\ No newline at end of file
+  compression: "gzip"
diff --git a/testdata/acceptance/lzma.compression.yaml b/testdata/acceptance/lzma.compression.yaml
index 3883bec..7cb17c1 100644
--- a/testdata/acceptance/lzma.compression.yaml
+++ b/testdata/acceptance/lzma.compression.yaml
@@ -9,9 +9,11 @@ description: |
 vendor: "foobar"
 homepage: "https://foobar.org"
 license: "MIT"
-files:
-  ./testdata/fake: "/usr/local/bin/fake"
-config_files:
-  ./testdata/whatever.conf: "/etc/foo/whatever.conf"
+contents:
+- src: ./testdata/fake
+  dst: /usr/local/bin/fake
+- src: ./testdata/whatever.conf
+  dst: /etc/foo/whatever.conf
+  type: config
 rpm:
-  compression: "lzma"
\ No newline at end of file
+  compression: "lzma"
diff --git a/testdata/acceptance/min.yaml b/testdata/acceptance/min.yaml
index eb5d377..a464f64 100644
--- a/testdata/acceptance/min.yaml
+++ b/testdata/acceptance/min.yaml
@@ -2,5 +2,6 @@ name: foo
 arch: amd64
 version: 1.2.3
 license: MIT
-files:
-  ./testdata/fake: "/usr/local/bin/fake"
+contents:
+- src: ./testdata/fake
+  dst: /usr/local/bin/fake
diff --git a/testdata/acceptance/overrides.yaml b/testdata/acceptance/overrides.yaml
index 3d7ab15..157f506 100644
--- a/testdata/acceptance/overrides.yaml
+++ b/testdata/acceptance/overrides.yaml
@@ -17,11 +17,14 @@ description: |
 vendor: "foobar"
 homepage: "https://foobar.org"
 license: "MIT"
-files:
-  ./testdata/fake: "/usr/local/bin/fake"
-  ./testdata/acceptance/folder/*: "/usr/share/whatever/folder/"
-config_files:
-  ./testdata/whatever.conf: "/etc/foo/whatever.conf"
+contents:
+- src: ./testdata/fake
+  dst: /usr/local/bin/fake
+- src: ./testdata/acceptance/folder/*
+  dst: /usr/share/whatever/folder/
+- src: ./testdata/whatever.conf
+  dst: /etc/foo/whatever.conf
+  type: config
 overrides:
   rpm:
     scripts:
diff --git a/testdata/acceptance/release.rpm.yaml b/testdata/acceptance/release.rpm.yaml
index cf0b6ac..d7ecc1c 100644
--- a/testdata/acceptance/release.rpm.yaml
+++ b/testdata/acceptance/release.rpm.yaml
@@ -10,7 +10,9 @@ description: |
 vendor: "foobar"
 homepage: "https://foobar.org"
 license: "MIT"
-files:
-  ./testdata/fake: "/usr/local/bin/fake"
-config_files:
-  ./testdata/whatever.conf: "/etc/foo/whatever.conf"
+contents:
+- src: ./testdata/fake
+  dst: /usr/local/bin/fake
+- src: ./testdata/whatever.conf
+  dst: /etc/foo/whatever.conf
+  type: config
diff --git a/testdata/acceptance/rules.deb.yaml b/testdata/acceptance/rules.deb.yaml
index d49da0f..05eb4ff 100644
--- a/testdata/acceptance/rules.deb.yaml
+++ b/testdata/acceptance/rules.deb.yaml
@@ -9,10 +9,12 @@ description: |
 vendor: "foobar"
 homepage: "https://foobar.org"
 license: "MIT"
-files:
-  ./testdata/fake: "/usr/local/bin/fake"
-config_files:
-  ./testdata/whatever.conf: "/etc/foo/whatever.conf"
+contents:
+- src: ./testdata/fake
+  dst: /usr/local/bin/fake
+- src: ./testdata/whatever.conf
+  dst: /etc/foo/whatever.conf
+  type: config
 deb:
   scripts:
     rules: ./testdata/acceptance/scripts/rules.sh
diff --git a/testdata/acceptance/signed.yaml b/testdata/acceptance/signed.yaml
index c77ee46..f28dfc5 100644
--- a/testdata/acceptance/signed.yaml
+++ b/testdata/acceptance/signed.yaml
@@ -6,8 +6,9 @@ maintainer: "John Doe <john@example.com>"
 description: This package is sigend
 vendor: "FooBarCorp"
 homepage: "http://example.com"
-files:
-  ./testdata/fake: "/usr/local/bin/fake"
+contents:
+- src: ./testdata/fake
+  dst: /usr/local/bin/fake
 deb:
   signature:
     key_file: ./internal/sign/testdata/privkey_unprotected.asc
diff --git a/testdata/acceptance/simple.386.yaml b/testdata/acceptance/simple.386.yaml
index 7a52923..94153ac 100644
--- a/testdata/acceptance/simple.386.yaml
+++ b/testdata/acceptance/simple.386.yaml
@@ -9,7 +9,9 @@ description: |
 vendor: "foobar"
 homepage: "https://foobar.org"
 license: "MIT"
-files:
-  ./testdata/fake: "/usr/local/bin/fake"
-config_files:
-  ./testdata/whatever.conf: "/etc/foo/whatever.conf"
+contents:
+- src: ./testdata/fake
+  dst: /usr/local/bin/fake
+- src: ./testdata/whatever.conf
+  dst: /etc/foo/whatever.conf
+  type: config
diff --git a/testdata/acceptance/simple.arm64.yaml b/testdata/acceptance/simple.arm64.yaml
index af7baae..d0b04f9 100644
--- a/testdata/acceptance/simple.arm64.yaml
+++ b/testdata/acceptance/simple.arm64.yaml
@@ -9,7 +9,9 @@ description: |
 vendor: "foobar"
 homepage: "https://foobar.org"
 license: "MIT"
-files:
-  ./testdata/fake: "/usr/local/bin/fake"
-config_files:
-  ./testdata/whatever.conf: "/etc/foo/whatever.conf"
+contents:
+- src: ./testdata/fake
+  dst: /usr/local/bin/fake
+- src: ./testdata/whatever.conf
+  dst: /etc/foo/whatever.conf
+  type: config
diff --git a/testdata/acceptance/simple.ppc64le.yaml b/testdata/acceptance/simple.ppc64le.yaml
index 90b89f2..4716582 100644
--- a/testdata/acceptance/simple.ppc64le.yaml
+++ b/testdata/acceptance/simple.ppc64le.yaml
@@ -9,7 +9,9 @@ description: |
 vendor: "foobar"
 homepage: "https://foobar.org"
 license: "MIT"
-files:
-  ./testdata/fake: "/usr/local/bin/fake"
-config_files:
-  ./testdata/whatever.conf: "/etc/foo/whatever.conf"
+contents:
+- src: ./testdata/fake
+  dst: /usr/local/bin/fake
+- src: ./testdata/whatever.conf
+  dst: /etc/foo/whatever.conf
+  type: config
diff --git a/testdata/acceptance/simple.yaml b/testdata/acceptance/simple.yaml
index 96e1cf9..fd499d8 100644
--- a/testdata/acceptance/simple.yaml
+++ b/testdata/acceptance/simple.yaml
@@ -10,7 +10,9 @@ description: |
 vendor: "foobar"
 homepage: "https://foobar.org"
 license: "MIT"
-files:
-  ./testdata/fake: "/usr/local/bin/fake"
-config_files:
-  ./testdata/whatever.conf: "/etc/foo/whatever.conf"
+contents:
+- src: ./testdata/fake
+  dst: /usr/local/bin/fake
+- src: ./testdata/whatever.conf
+  dst: /etc/foo/whatever.conf
+  type: config
diff --git a/testdata/acceptance/symlink.yaml b/testdata/acceptance/symlink.yaml
index 4fb64d7..b20d8f6 100644
--- a/testdata/acceptance/symlink.yaml
+++ b/testdata/acceptance/symlink.yaml
@@ -6,7 +6,9 @@ maintainer: "Foo Bar"
 vendor: "foobar"
 homepage: "https://foobar.org"
 license: "MIT"
-files:
-  ./testdata/whatever.conf: "/etc/foo/whatever.conf"
-symlinks:
-  /path/to/symlink: "/etc/foo/whatever.conf"
+contents:
+- src: ./testdata/whatever.conf
+  dst: /etc/foo/whatever.conf
+- src: /etc/foo/whatever.conf
+  dst: /path/to/symlink
+  type: symlink
diff --git a/testdata/acceptance/triggers.yaml b/testdata/acceptance/triggers.yaml
index 614f7d5..e8dee48 100644
--- a/testdata/acceptance/triggers.yaml
+++ b/testdata/acceptance/triggers.yaml
@@ -5,8 +5,9 @@ version: "v1.2.3-beta"
 maintainer: "Foo Bar"
 vendor: "foobar"
 license: "MIT"
-files:
-  ./testdata/fake: "/usr/local/bin/fake"
+contents:
+- src: ./testdata/fake
+  dst: /usr/local/bin/fake
 scripts:
   postinstall: ./testdata/acceptance/scripts/postinstall_trigger.sh
 deb:
diff --git a/testdata/acceptance/withchangelog.yaml b/testdata/acceptance/withchangelog.yaml
index 6eb3683..5fdf9f5 100644
--- a/testdata/acceptance/withchangelog.yaml
+++ b/testdata/acceptance/withchangelog.yaml
@@ -11,7 +11,9 @@ description: |
 vendor: "foobar"
 homepage: "https://foobar.org"
 license: "MIT"
-files:
-  ./testdata/fake: "/usr/local/bin/fake"
-config_files:
-  ./testdata/whatever.conf: "/etc/foo/whatever.conf"
+contents:
+- src: ./testdata/fake
+  dst: /usr/local/bin/fake
+- src: ./testdata/whatever.conf
+  dst: /etc/foo/whatever.conf
+  type: config
diff --git a/testdata/acceptance/xz.compression.yaml b/testdata/acceptance/xz.compression.yaml
index db61cd6..611881f 100644
--- a/testdata/acceptance/xz.compression.yaml
+++ b/testdata/acceptance/xz.compression.yaml
@@ -9,9 +9,11 @@ description: |
 vendor: "foobar"
 homepage: "https://foobar.org"
 license: "MIT"
-files:
-  ./testdata/fake: "/usr/local/bin/fake"
-config_files:
-  ./testdata/whatever.conf: "/etc/foo/whatever.conf"
+contents:
+- src: ./testdata/fake
+  dst: /usr/local/bin/fake
+- src: ./testdata/whatever.conf
+  dst: /etc/foo/whatever.conf
+  type: config
 rpm:
-  compression: "xz"
\ No newline at end of file
+  compression: "xz"
diff --git a/testdata/overrides.yaml b/testdata/overrides.yaml
index 84182cf..b7b1077 100644
--- a/testdata/overrides.yaml
+++ b/testdata/overrides.yaml
@@ -2,23 +2,31 @@
 name: "foo"
 arch: "amd64"
 version: "v1.2.3"
-config_files:
-  whatever.conf: "/etc/foo/whatever.conf"
+contents:
+- src: ./testdata/whatever.conf
+  dst: /etc/foo/whatever.conf
+  type: config
+- src: ./testdata/whatever.conf
+  dst: /deb/path.conf
+  type: config
+  packager: deb
+- src: ./testdata/whatever.conf
+  dst: /rpm/path.conf
+  type: config
+  packager: rpm
+- src: ./testdata/whatever.conf
+  dst: /apk/path.conf
+  type: config
+  packager: apk
 rpm:
   group: foo
 overrides:
   deb:
     depends:
       - deb_depend
-    config_files:
-      deb.conf: "/deb/path"
   rpm:
     depends:
       - rpm_depend
-    config_files:
-      rpm.conf: "/rpm/path"
   apk:
     depends:
       - apk_depend
-    config_files:
-      apk.conf: "/apk/path"
diff --git a/testdata/versionenv.yaml b/testdata/versionenv.yaml
index cff67d0..3ac954d 100644
--- a/testdata/versionenv.yaml
+++ b/testdata/versionenv.yaml
@@ -2,16 +2,22 @@
 name: "foo"
 arch: "amd64"
 version: "v$GOROOT"
-config_files:
-  whatever.conf: "/etc/foo/whatever.conf"
+contents:
+- src: ./testdata/whatever.conf
+  dst: /etc/foo/regular.conf
+  type: config
+- src: ./testdata/whatever.conf
+  dst: /deb/path
+  type: config
+  packager: deb
+- src: ./testdata/whatever.conf
+  dst: /rpm/path
+  type: config
+  packager: rpm
 overrides:
   deb:
     depends:
       - deb_depend
-    config_files:
-      deb.conf: "/deb/path"
   rpm:
     depends:
       - rpm_depend
-    config_files:
-      rpm.conf: "/rpm/path"