1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-01-10 03:47:03 +02:00
goreleaser/internal/archivefiles/archivefiles.go
Carlos Alexandro Becker b5e8d6db06
fix(archive): warn only for non-default globs with no matches (#4013)
Adjust the logging of warnings for unmatched globs to only show when the
glob is not a default. No warning will be output for the default globs
when there are no matching files.

These are defaults, by design, very generic.
We should not warn the user about them not finding anything, as that is
their expected behavior most of the time.
2023-05-16 09:22:22 -03:00

162 lines
3.9 KiB
Go

// Package archivefiles can evaluate a list of config.Files into their final form.
package archivefiles
import (
"errors"
"fmt"
"io/fs"
"os"
"path/filepath"
"sort"
"time"
"github.com/caarlos0/log"
"github.com/goreleaser/fileglob"
"github.com/goreleaser/goreleaser/internal/tmpl"
"github.com/goreleaser/goreleaser/pkg/config"
)
// Eval evaluates the given list of files to their final form.
func Eval(template *tmpl.Template, rlcp bool, files []config.File) ([]config.File, error) {
var result []config.File
for _, f := range files {
glob, err := template.Apply(f.Source)
if err != nil {
return result, fmt.Errorf("failed to apply template %s: %w", f.Source, err)
}
files, err := fileglob.Glob(glob)
if err != nil {
return result, fmt.Errorf("globbing failed for pattern %s: %w", glob, err)
}
if len(files) == 0 {
if !f.Default {
// only log if its not a default glob, as those are usually
// very generic and are not really warnings for the user.
log.WithField("glob", f.Source).Warn("no files matched")
}
continue
}
if err := tmplInfo(template, &f.Info); err != nil {
return result, err
}
// the prefix may not be a complete path or may use glob patterns, in that case use the parent directory
prefix := glob
if _, err := os.Stat(prefix); errors.Is(err, fs.ErrNotExist) || fileglob.ContainsMatchers(prefix) {
prefix = filepath.Dir(longestCommonPrefix(files))
}
for _, file := range files {
dst, err := destinationFor(f, prefix, file, rlcp)
if err != nil {
return nil, err
}
result = append(result, config.File{
Source: file,
Destination: dst,
Info: f.Info,
})
}
}
sort.Slice(result, func(i, j int) bool {
return result[i].Destination < result[j].Destination
})
return unique(result), nil
}
func tmplInfo(template *tmpl.Template, info *config.FileInfo) error {
var err error
info.Owner, err = template.Apply(info.Owner)
if err != nil {
return fmt.Errorf("failed to apply template %s: %w", info.Owner, err)
}
info.Group, err = template.Apply(info.Group)
if err != nil {
return fmt.Errorf("failed to apply template %s: %w", info.Group, err)
}
info.MTime, err = template.Apply(info.MTime)
if err != nil {
return fmt.Errorf("failed to apply template %s: %w", info.MTime, err)
}
if info.MTime != "" {
info.ParsedMTime, err = time.Parse(time.RFC3339Nano, info.MTime)
if err != nil {
return fmt.Errorf("failed to parse %s: %w", info.MTime, err)
}
}
return nil
}
// remove duplicates
func unique(in []config.File) []config.File {
var result []config.File
exist := map[string]string{}
for _, f := range in {
if current := exist[f.Destination]; current != "" {
log.Warnf(
"file '%s' already exists in archive as '%s' - '%s' will be ignored",
f.Destination,
current,
f.Source,
)
continue
}
exist[f.Destination] = f.Source
result = append(result, f)
}
return result
}
func destinationFor(f config.File, prefix, path string, rlcp bool) (string, error) {
if f.StripParent {
return filepath.Join(f.Destination, filepath.Base(path)), nil
}
if rlcp && f.Destination != "" {
relpath, err := filepath.Rel(prefix, path)
if err != nil {
// since prefix is a prefix of src a relative path should always be found
return "", err
}
return filepath.ToSlash(filepath.Join(f.Destination, relpath)), nil
}
return filepath.Join(f.Destination, path), nil
}
// longestCommonPrefix returns the longest prefix of all strings the argument
// slice. If the slice is empty the empty string is returned.
// copied from nfpm
func longestCommonPrefix(strs []string) string {
if len(strs) == 0 {
return ""
}
lcp := strs[0]
for _, str := range strs {
lcp = strlcp(lcp, str)
}
return lcp
}
// copied from nfpm
func strlcp(a, b string) string {
var min int
if len(a) > len(b) {
min = len(b)
} else {
min = len(a)
}
for i := 0; i < min; i++ {
if a[i] != b[i] {
return a[0:i]
}
}
return a[0:min]
}