Skip to content

Commit

Permalink
pack: support .packignore
Browse files Browse the repository at this point in the history
In some cases, there are files that may be useful, but should not
be part of artifact. The ability to add files and directories to
the .packignore file has been added, which allows you to ignore
these files and directories when packing.

Closes #812
  • Loading branch information
elhimov committed Feb 4, 2025
1 parent b7ebf79 commit dbf7cd6
Show file tree
Hide file tree
Showing 2 changed files with 164 additions and 0 deletions.
109 changes: 109 additions & 0 deletions cli/pack/common.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package pack

import (
"bufio"
"errors"
"fmt"
"io"
"io/fs"
"os"
"path/filepath"
Expand Down Expand Up @@ -33,6 +36,8 @@ const (
versionLuaFileName = "VERSION.lua"

rocksManifestPath = ".rocks/share/tarantool/rocks/manifest"

ignoreFile = ".packignore"
)

var (
Expand Down Expand Up @@ -157,6 +162,103 @@ func previousPackageFilters(packCtx *PackCtx) []func(
}
}

func ignorePatternToRegex(pattern string) (string, bool, bool) {
onlyDirs := strings.HasSuffix(pattern, "/")
if onlyDirs {
pattern = pattern[:len(pattern)-1]
}

negate := false
if strings.HasPrefix(pattern, "!") {
negate = true
pattern = pattern[1:]
} else {
if strings.HasPrefix(pattern, "\\!") || strings.HasPrefix(pattern, "\\#") {
pattern = pattern[1:]
}
}

expr := pattern
expr = strings.ReplaceAll(expr, "/**/", "/([^/]+/)*")
// expr = strings.ReplaceAll(expr, "**/", "([^/]+/w)*")
// expr = strings.ReplaceAll(expr, "/**", "[^/]*")
expr = strings.ReplaceAll(expr, "*", "[^/]*")
expr = strings.ReplaceAll(expr, "?", "[^/]")
return expr, negate, onlyDirs
}

// ignoreFilter returns filter that excludes files based on the patterns.
func ignoreFilter(packCtx *PackCtx, patterns io.Reader) func(
srcInfo os.FileInfo, src string) bool {

var exprExclude, exprInclude, exprExcludeDirs, exprIncludeDirs []string

s := bufio.NewScanner(patterns)
for s.Scan() {
pattern := strings.TrimSpace(s.Text())
if pattern == "" || strings.HasPrefix(pattern, "#") {
continue
}

exprPart, negate, onlyDirs := ignorePatternToRegex(pattern)

var expr *[]string
if onlyDirs {
if negate {
expr = &exprIncludeDirs
} else {
expr = &exprExcludeDirs
}
} else {
if negate {
expr = &exprInclude
} else {
expr = &exprExclude
}
}
*expr = append(*expr, "("+exprPart+")")
}

compileRegexp := func(expr []string) *regexp.Regexp {
if len(exprInclude) == 0 {
return nil
}
re, err := regexp.Compile(strings.Join(expr, "|"))
if err != nil {
return nil
}
return re
}

reInclude := compileRegexp(exprInclude)
reExclude := compileRegexp(exprExclude)
reIncludeDirs := compileRegexp(exprIncludeDirs)
reExcludeDirs := compileRegexp(exprExcludeDirs)

return func(srcInfo os.FileInfo, src string) bool {
// Skip ignore file itself.
if filepath.Base(src) == ignoreFile {
return true
}
// If it's directory first check patterns that only match directories.
if srcInfo.IsDir() {
if reIncludeDirs != nil && reIncludeDirs.MatchString(src) {
return false
}
if reExcludeDirs != nil && reExcludeDirs.MatchString(src) {
return true
}
}
if reInclude != nil && reInclude.MatchString(src) {
return false
}
if reExclude != nil && reExclude.MatchString(src) {
return true
}
return false
}
}

// appSrcCopySkip returns a filter func to filter out artifacts paths.
func appSrcCopySkip(packCtx *PackCtx, cliOpts *config.CliOpts,
srcAppPath string) func(srcinfo os.FileInfo, src, dest string) (bool, error) {
Expand All @@ -166,6 +268,13 @@ func appSrcCopySkip(packCtx *PackCtx, cliOpts *config.CliOpts,
appCopyFilters = append(appCopyFilters, func(srcInfo os.FileInfo, src string) bool {
return skipDefaults(srcInfo, src)
})
f, err := os.Open(ignoreFile)
if err == nil || errors.Is(err, fs.ErrNotExist) {
appCopyFilters = append(appCopyFilters, ignoreFilter(packCtx, f))
f.Close()
} else {
log.Errorf("Failed to open ignore file %q: %w", ignoreFile, err)
}

return func(srcinfo os.FileInfo, src, dest string) (bool, error) {
for _, shouldSkip := range appCopyFilters {
Expand Down
55 changes: 55 additions & 0 deletions cli/pack/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"path/filepath"
"strings"
"testing"
"testing/fstest"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -1106,3 +1107,57 @@ func Test_prepareBundle(t *testing.T) {
})
}
}

func Test_ignoreFilter(t *testing.T) {
type testFile struct {
path string
expected bool
}

type testCase struct {
name string
patterns []string
files []testFile
}

testCases := []testCase{
{
name: "single pattern",
patterns: []string{
"/test",
},
files: []testFile{
{"test", true},
{"test2", false},
},
},
{
name: "single pattern negate",
patterns: []string{
"!/test",
},
files: []testFile{
{"test", false},
{"test2", false},
},
},
}

for _, testCase := range testCases {
patterns := strings.Join(testCase.patterns, "\n")
f := ignoreFilter(include, strings.NewReader(patterns))

Check failure on line 1148 in cli/pack/common_test.go

View workflow job for this annotation

GitHub Actions / tests-ee (2.11.2-0-r609.linux.x86_64)

undefined: include (typecheck)

Check failure on line 1148 in cli/pack/common_test.go

View workflow job for this annotation

GitHub Actions / tests-ce (1.10)

undefined: include (typecheck)

Check failure on line 1148 in cli/pack/common_test.go

View workflow job for this annotation

GitHub Actions / tests-ee (3.2.0-0-r40.linux.x86_64)

undefined: include (typecheck)

Check failure on line 1148 in cli/pack/common_test.go

View workflow job for this annotation

GitHub Actions / tests-ce (2.10)

undefined: include (typecheck)

Check failure on line 1148 in cli/pack/common_test.go

View workflow job for this annotation

GitHub Actions / tests-ce (3.0)

undefined: include (typecheck)

t.Run(testCase.name, func(t *testing.T) {
var testFs fstest.MapFS
for _, file := range testCase.files {
testFs[file.path] = &fstest.MapFile{}
}
for _, file := range testCase.files {
fi, err := testFs.Stat(file.path)
assert.Equal(t, nil, err)
actual := f(fi, file.path)
assert.Equal(t, file.expected, actual)
}
})
}
}

0 comments on commit dbf7cd6

Please sign in to comment.