diff --git a/pkg/client/client.go b/pkg/client/client.go index c4e73c53..a2a17a56 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -696,7 +696,7 @@ func (c *KpmClient) Package(kclPkg *pkg.KclPkg, tarPath string, vendorMode bool) } // Tar the current kcl package into a "*.tar" file. - err := utils.TarDir(kclPkg.HomePath, tarPath) + err := utils.TarDir(kclPkg.HomePath, tarPath, kclPkg.GetPkgInclude(), kclPkg.GetPkgExclude()) if err != nil { return reporter.NewErrorEvent(reporter.FailedPackage, err, "failed to package the kcl module") } diff --git a/pkg/package/modfile.go b/pkg/package/modfile.go index 95a5832d..9c59f06f 100644 --- a/pkg/package/modfile.go +++ b/pkg/package/modfile.go @@ -28,10 +28,12 @@ const ( // 'Package' is the kcl package section of 'kcl.mod'. type Package struct { - Name string `toml:"name,omitempty"` // kcl package name - Edition string `toml:"edition,omitempty"` // kcl compiler version - Version string `toml:"version,omitempty"` // kcl package version - Description string `toml:"description,omitempty"` // kcl package description + Name string `toml:"name,omitempty"` // kcl package name + Edition string `toml:"edition,omitempty"` // kcl compiler version + Version string `toml:"version,omitempty"` // kcl package version + Description string `toml:"description,omitempty"` // kcl package description + Include []string `toml:"include,omitempty"` // kcl package include + Exclude []string `toml:"exclude,omitempty"` // kcl package exclude } // 'ModFile' is kcl package file 'kcl.mod'. diff --git a/pkg/package/package.go b/pkg/package/package.go index 91dd547d..9eba0634 100644 --- a/pkg/package/package.go +++ b/pkg/package/package.go @@ -288,6 +288,16 @@ func (KclPkg *KclPkg) GetPkgDescription() string { return KclPkg.ModFile.Pkg.Description } +// GetPkgInclude returns the include of package. +func (KclPkg *KclPkg) GetPkgInclude() []string { + return KclPkg.ModFile.Pkg.Include +} + +// GetPkgExclude returns the exclude of package. +func (KclPkg *KclPkg) GetPkgExclude() []string { + return KclPkg.ModFile.Pkg.Exclude +} + // GenCheckSum generates the checksum of the current kcl package. func (KclPkg *KclPkg) GenCheckSum() (string, error) { return utils.HashDir(KclPkg.HomePath) diff --git a/pkg/package/test_data/test_data_toml/expected.toml b/pkg/package/test_data/test_data_toml/expected.toml index 4d9b4c16..7bb599e9 100644 --- a/pkg/package/test_data/test_data_toml/expected.toml +++ b/pkg/package/test_data/test_data_toml/expected.toml @@ -2,6 +2,8 @@ name = "MyKcl" edition = "v0.0.1" version = "v0.0.1" +include = ["src/", "README.md", "LICENSE"] +exclude = ["target/", ".git/", "*.log"] [dependencies] MyOciKcl1 = "0.0.1" diff --git a/pkg/package/toml.go b/pkg/package/toml.go index 6bc8a34e..904a3b22 100644 --- a/pkg/package/toml.go +++ b/pkg/package/toml.go @@ -231,6 +231,8 @@ const NAME_FLAG = "name" const EDITION_FLAG = "edition" const VERSION_FLAG = "version" const DESCRIPTION_FLAG = "description" +const INCLUDE_FLAG = "include" +const EXCLUDE_FLAG = "exclude" func (pkg *Package) UnmarshalTOML(data interface{}) error { meta, ok := data.(map[string]interface{}) @@ -253,6 +255,23 @@ func (pkg *Package) UnmarshalTOML(data interface{}) error { if v, ok := meta[DESCRIPTION_FLAG].(string); ok { pkg.Description = v } + + convertToStringArray := func(v interface{}) []string { + var arr []string + for _, item := range v.([]interface{}) { + arr = append(arr, item.(string)) + } + return arr + } + + if v, ok := meta[INCLUDE_FLAG].([]interface{}); ok { + pkg.Include = convertToStringArray(v) + } + + if v, ok := meta[EXCLUDE_FLAG].([]interface{}); ok { + pkg.Exclude = convertToStringArray(v) + } + return nil } diff --git a/pkg/package/toml_test.go b/pkg/package/toml_test.go index 0b0e78c3..71f9eca5 100644 --- a/pkg/package/toml_test.go +++ b/pkg/package/toml_test.go @@ -77,6 +77,8 @@ func TestUnMarshalTOML(t *testing.T) { assert.Equal(t, modfile.Pkg.Name, "MyKcl") assert.Equal(t, modfile.Pkg.Edition, "v0.0.1") assert.Equal(t, modfile.Pkg.Version, "v0.0.1") + assert.Equal(t, modfile.Pkg.Include, []string{"src/", "README.md", "LICENSE"}) + assert.Equal(t, modfile.Pkg.Exclude, []string{"target/", ".git/", "*.log"}) assert.Equal(t, len(modfile.Dependencies.Deps), 2) assert.NotEqual(t, modfile.Dependencies.Deps["MyKcl1"], nil) assert.Equal(t, modfile.Dependencies.Deps["MyKcl1"].Name, "MyKcl1") diff --git a/pkg/utils/test_data/test_tar/test_src/test.mod b/pkg/utils/test_data/test_tar/test_src/test.mod new file mode 100644 index 00000000..e69de29b diff --git a/pkg/utils/test_data/test_tar/test_src/test.txt b/pkg/utils/test_data/test_tar/test_src/test.txt new file mode 100644 index 00000000..e69de29b diff --git a/pkg/utils/test_data/test_tar/test_src/test_tar_dir/test_1.lock b/pkg/utils/test_data/test_tar/test_src/test_tar_dir/test_1.lock new file mode 100644 index 00000000..e69de29b diff --git a/pkg/utils/test_data/test_tar/test_src/test_tar_dir/test_1.txt b/pkg/utils/test_data/test_tar/test_src/test_tar_dir/test_1.txt new file mode 100644 index 00000000..e69de29b diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 02fd9c65..2c6e8151 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -126,8 +126,7 @@ func Exists(path string) (bool, error) { // todo: Consider using the OCI tarball as the standard tar format. var ignores = []string{".git", ".tar"} -func TarDir(srcDir string, tarPath string) error { - +func TarDir(srcDir string, tarPath string, include []string, exclude []string) error { fw, err := os.Create(tarPath) if err != nil { log.Fatal(err) @@ -148,6 +147,26 @@ func TarDir(srcDir string, tarPath string) error { } } + getNewPattern := func(ex string) string { + newPath := ex + if !strings.HasPrefix(ex, srcDir + "/") { + newPath = srcDir + "/" + ex + } + return newPath + } + + for _, ex := range exclude { + if matched, _ := filepath.Match(getNewPattern(ex), path); matched { + return nil + } + } + + for _, inc := range include { + if matched, _ := filepath.Match(getNewPattern(inc), path); !matched { + return nil + } + } + relPath, _ := filepath.Rel(srcDir, path) relPath = filepath.ToSlash(relPath) diff --git a/pkg/utils/utils_test.go b/pkg/utils/utils_test.go index 2ab8a51b..d52558eb 100644 --- a/pkg/utils/utils_test.go +++ b/pkg/utils/utils_test.go @@ -1,8 +1,12 @@ package utils import ( + "archive/tar" + "io" "os" + "path" "path/filepath" + "strings" "testing" "github.com/stretchr/testify/assert" @@ -75,9 +79,67 @@ func TestTarDir(t *testing.T) { os.Remove(tarPath) } - err = TarDir(filepath.Join(testDir, "test_src"), tarPath) + testSrcDir := filepath.Join(testDir, "test_src") + + getTarFileNames := func(filePath string) ([]string, error) { + file, err := os.Open(filePath) + if err != nil { + return nil, err + } + defer file.Close() + + reader := tar.NewReader(file) + filePaths := []string{} + + for { + header, err := reader.Next() + if err == io.EOF { + break + } + if err != nil { + return nil, err + } + + if header.Typeflag != tar.TypeReg { + continue + } + + fullPath := path.Join(header.Name) + fullPath = path.Join(filePath, fullPath) + fullPath = strings.Replace(fullPath, "test.tar", "test_src", 1) + + filePaths = append(filePaths, fullPath) + } + + return filePaths, nil + } + + getNewPattern := func(ex string) string { + return testSrcDir + "/" + ex + } + + err = TarDir(testSrcDir, tarPath, []string{}, []string{}) + assert.Equal(t, err, nil) + _, err = os.Stat(tarPath) + assert.Equal(t, err, nil) + os.Remove(tarPath) + + _ = TarDir(testSrcDir, tarPath, []string{}, []string{"*.mod"}) + fileNames, _ := getTarFileNames(tarPath) + for _, fileName := range fileNames { + flag, _ := filepath.Match(getNewPattern("*.mod"), fileName) + assert.Equal(t, flag, false) + } + _, err = os.Stat(tarPath) assert.Equal(t, err, nil) + os.Remove(tarPath) + _ = TarDir(testSrcDir, tarPath, []string{"*/*.lock", "*.mod"}, []string{}) + fileNames, _ = getTarFileNames(tarPath) + for _, fileName := range fileNames { + flag, _ := filepath.Match(getNewPattern("*/*.lock"), fileName) + assert.Equal(t, flag, true) + } _, err = os.Stat(tarPath) assert.Equal(t, err, nil) os.Remove(tarPath)