Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Added "excludes" option to prevent packing unnecessary files #822

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions files/files.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ type Content struct {
Packager string `yaml:"packager,omitempty" json:"packager,omitempty"`
FileInfo *ContentFileInfo `yaml:"file_info,omitempty" json:"file_info,omitempty"`
Expand bool `yaml:"expand,omitempty" json:"expand,omitempty"`
Excludes []string `yaml:"excludes,omitempty" json:"excludes,omitempty"`
}

type ContentFileInfo struct {
Expand Down Expand Up @@ -471,6 +472,15 @@ func addTree(

destination := filepath.Join(tree.Destination, relPath)

if tree.Excludes != nil {
// Check if src matches any of the exclude patterns
for _, exclude := range tree.Excludes {
if strings.Contains(destination, exclude) {
return nil
}
}
}

c := &Content{
FileInfo: &ContentFileInfo{},
}
Expand Down
51 changes: 51 additions & 0 deletions files/files_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -931,6 +931,57 @@ func TestTreeMode(t *testing.T) {
}
}

func TestExcludesTree(t *testing.T) {
results, err := files.PrepareForPackager(
files.Contents{
{
Source: filepath.Join("testdata", "tree"),
Destination: "/base",
Type: files.TypeTree,
Excludes: []string{"/base/files/b"},
},
},
0,
"",
false,
mtime,
)
require.NoError(t, err)

require.Equal(t, files.Contents{
{
Source: "",
Destination: "/base/",
Type: files.TypeDir,
},
{
Source: "",
Destination: "/base/files/",
Type: files.TypeDir,
},
{
Source: filepath.Join("testdata", "tree", "files", "a"),
Destination: "/base/files/a",
Type: files.TypeFile,
},
{
Source: "",
Destination: "/base/symlinks/",
Type: files.TypeDir,
},
{
Source: "/etc/foo",
Destination: "/base/symlinks/link1",
Type: files.TypeSymlink,
},
{
Source: "../files/a",
Destination: "/base/symlinks/link2",
Type: files.TypeSymlink,
},
}, withoutFileInfo(results))
}

func withoutFileInfo(contents files.Contents) files.Contents {
filtered := make(files.Contents, 0, len(contents))

Expand Down
32 changes: 30 additions & 2 deletions internal/glob/glob.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,18 @@ func (e ErrGlobNoMatch) Error() string {
return fmt.Sprintf("glob failed: %s: no matching files", e.glob)
}

func Glob(pattern, dst string, ignoreMatchers bool) (map[string]string, error) {
return globCommon(pattern, dst, ignoreMatchers, nil)
}

func GlobExcludes(pattern, dst string, excludes []string) (map[string]string, error) {
return globCommon(pattern, dst, false, excludes)
}

// Glob returns a map with source file path as keys and destination as values.
// First the longest common prefix (lcp) of all globbed files is found. The destination
// for each globbed file is then dst joined with src with the lcp trimmed off.
func Glob(pattern, dst string, ignoreMatchers bool) (map[string]string, error) {
func globCommon(pattern, dst string, ignoreMatchers bool, excludes []string) (map[string]string, error) {
options := []fileglob.OptFunc{fileglob.MatchDirectoryIncludesContents}
if ignoreMatchers {
options = append(options, fileglob.QuoteMeta)
Expand Down Expand Up @@ -106,7 +114,27 @@ func Glob(pattern, dst string, ignoreMatchers bool) (map[string]string, error) {
return nil, err
}

globdst := filepath.ToSlash(filepath.Join(dst, relpath))
dst_relpath := filepath.Join(dst, relpath)

// Check if src matches any of the exclude patterns
if excludes != nil {
excluded := false
for _, exclude := range excludes {
matched, err := filepath.Match(exclude, dst_relpath)
if err != nil {
return nil, fmt.Errorf("failed to match exclude pattern: %s: %w", exclude, err)
}
if matched {
excluded = true
break
}
}
if excluded {
continue
}
}

globdst := filepath.ToSlash(dst_relpath)
files[src] = globdst
}

Expand Down
8 changes: 8 additions & 0 deletions internal/glob/glob_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,12 @@ func TestGlob(t *testing.T) {
require.Len(t, files, 1)
require.Equal(t, "/foo/bar/dest.dat", files["testdata/dir_a/dir_b/test_b.txt"])
})

t.Run("simple excludes", func(t *testing.T) {
var excludes []string = []string{"/foo/bar/dir_c/*"}
files, err := GlobExcludes("./testdata/dir_a/dir_*/*", "/foo/bar", excludes)
require.NoError(t, err)
require.Len(t, files, 1)
require.Equal(t, "/foo/bar/dir_b/test_b.txt", files["testdata/dir_a/dir_b/test_b.txt"])
})
}
18 changes: 17 additions & 1 deletion www/docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ contents:
- src: path/to/local/*.1.gz
dst: /usr/share/man/man1/

# Simple symlink at /usr/bin/foo which points to /sbin/foo, which is
# Simple symlink at /usr/bin/foo which points to /sbin/foo, which is
# the same behaviour as `ln -s /sbin/foo /usr/bin/foo`.
#
# This also means that both "src" and "dst" are paths inside the package (or
Expand Down Expand Up @@ -266,6 +266,22 @@ contents:
src: "${NAME}"
expand: true

# This replicates the directory structure from some/directory to /etc.
# By specifying "excludes", directories under /etc/ are not duplicated.
# If "excludes -/etc/dir_c" is set, then some/directory/dir_c will not be replicated.
- src: some/directory/
dst: /etc
type: tree
excludes:
- /etc/dir_c

# Select files in glob.
# Set "excludes" to exclude files from being copied to dst
- src: path/to/local/*.1.gz
dst: /usr/share/man/man1/
excludes:
- /usr/share/man/man1/*a.1.gz

# Umask to be used on files without explicit mode set.
#
# By default, nFPM will inherit the mode of the original file that's being
Expand Down
8 changes: 7 additions & 1 deletion www/docs/static/schema.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.