func ToNixPath(path string) string {
	return filepath.ToSlash(filepath.Clean(path))
}
ToNixPath converts the given path to a nix-style path.

Windows-style path separators are considered escape
characters by some libraries, which can cause issues.
package files
import (
	"fmt"
	"os"
	"path/filepath"
	"sort"
	"time"
	"github.com/goreleaser/fileglob"
	"github.com/goreleaser/nfpm/v2/internal/glob"
)
type Content struct {
	Source      string           `yaml:"src,omitempty"`
	Destination string           `yaml:"dst,omitempty"`
	Type        string           `yaml:"type,omitempty"`
	Packager    string           `yaml:"packager,omitempty"`
	FileInfo    *ContentFileInfo `yaml:"file_info,omitempty"`
}
type ContentFileInfo struct {
	Owner string      `yaml:"owner,omitempty"`
	Group string      `yaml:"group"`
	Mode  os.FileMode `yaml:"mode,omitempty"`
	MTime time.Time   `yaml:"mtime,omitempty"`
	Size  int64       `yaml:"-"`
}
type Contents []*Content
func (c Contents) Len() int {
	return len(c)
}
func (c Contents) Swap(i, j int) {
	c[i], c[j] = c[j], c[i]
}
func (c Contents) Less(i, j int) bool {
	a, b := c[i], c[j]
	if a.Type != b.Type {
		return len(a.Type) < len(b.Type)
	}
	if a.Source != b.Source {
		return a.Source < b.Source
	}
	return a.Destination < b.Destination
}
func (c *Content) WithFileInfoDefaults() *Content {
	cc := &Content{
		Source:      c.Source,
		Destination: c.Destination,
		Type:        c.Type,
		Packager:    c.Packager,
		FileInfo:    c.FileInfo,
	}
	if cc.FileInfo == nil {
		cc.FileInfo = &ContentFileInfo{}
	}
	if cc.FileInfo.Owner == "" {
		cc.FileInfo.Owner = "root"
	}
	if cc.FileInfo.Group == "" {
		cc.FileInfo.Group = "root"
	}
	info, err := os.Stat(cc.Source)
	if err == nil {
		if cc.FileInfo.MTime.IsZero() {
			cc.FileInfo.MTime = info.ModTime()
		}
		if cc.FileInfo.Mode == 0 {
			cc.FileInfo.Mode = info.Mode()
		}
		cc.FileInfo.Size = info.Size()
	}
	if cc.FileInfo.MTime.IsZero() {
		cc.FileInfo.MTime = time.Now().UTC()
	}
	return cc
}
func (c *Content) Name() string {
	return c.Source
}
func (c *Content) Size() int64 {
	return c.FileInfo.Size
}
func (c *Content) Mode() os.FileMode {
	return c.FileInfo.Mode
}
func (c *Content) ModTime() time.Time {
	return c.FileInfo.MTime
}
func (c *Content) IsDir() bool {
	return false
}
func (c *Content) Sys() interface{} {
	return nil
}
func ExpandContentGlobs(contents Contents, disableGlobbing bool) (files Contents, err error) {
	for _, f := range contents {
		var globbed map[string]string
		switch f.Type {
		case "ghost", "symlink":
			files, err = appendWithUniqueDestination(files, f.WithFileInfoDefaults())
			if err != nil {
				return nil, err
			}
			continue
		}
		options := []fileglob.OptFunc{fileglob.MatchDirectoryIncludesContents}
		if disableGlobbing {
			options = append(options, fileglob.QuoteMeta)
		}
		globbed, err = glob.Glob(f.Source, f.Destination, options...)
		if err != nil {
			return nil, err
		}
		files, err = appendGlobbedFiles(globbed, f, files)
		if err != nil {
			return nil, err
		}
	}
	sort.Sort(files)
	return files, nil
}
func appendGlobbedFiles(globbed map[string]string, origFile *Content, incFiles Contents) (files Contents, err error) {
	files = append(files, incFiles...)
	for src, dst := range globbed {
		newFile := &Content{
			Destination: ToNixPath(dst),
			Source:      ToNixPath(src),
			Type:        origFile.Type,
			FileInfo:    origFile.FileInfo,
			Packager:    origFile.Packager,
		}
		files, err = appendWithUniqueDestination(files, newFile.WithFileInfoDefaults())
		if err != nil {
			return nil, err
		}
	}
	return files, nil
}
var ErrContentCollision = fmt.Errorf("content collision")
func appendWithUniqueDestination(slice []*Content, elems ...*Content) ([]*Content, error) {
	alreadyPresent := map[string]*Content{}
	for _, presentElem := range slice {
		alreadyPresent[presentElem.Destination] = presentElem
	}
	for _, elem := range elems {
		present, ok := alreadyPresent[elem.Destination]
		if ok && (present.Packager == "" || elem.Packager == "" || present.Packager == elem.Packager) {
			return nil, fmt.Errorf(
				"cannot add %s because %s is already present at the same destination (%s): %w",
				elem.Source, present.Source, present.Destination, ErrContentCollision)
		}
		alreadyPresent[elem.Destination] = elem
	}
	return append(slice, elems...), nil
}