From d9fd1456f8658a21f316e2ea3aed037ca719c6ba Mon Sep 17 00:00:00 2001 From: Dominik Przybyl Date: Thu, 12 Sep 2024 20:36:20 +0200 Subject: [PATCH] refactor content sync --- cmd/aem/content.go | 66 ++++++-- cmd/aem/package.go | 6 +- pkg/common/pathx/pathx.go | 4 +- pkg/content/content.go | 207 ++---------------------- pkg/content_manager.go | 88 ++++------ pkg/oak_run.go | 4 +- pkg/package_manager.go | 61 +++---- pkg/pkg/vault/META-INF/vault/filter.xml | 7 +- pkg/test/clear_file_test.go | 23 +++ pkg/test/filter_file_test.go | 39 +++++ pkg/test/filter_root_test.go | 37 +++++ pkg/test/output.go | 6 + pkg/test/output/exclude_patterns.xml | 7 + pkg/test/output/filter_roots.xml | 5 + 14 files changed, 255 insertions(+), 305 deletions(-) create mode 100644 pkg/test/clear_file_test.go create mode 100644 pkg/test/filter_file_test.go create mode 100644 pkg/test/filter_root_test.go create mode 100644 pkg/test/output.go create mode 100644 pkg/test/output/exclude_patterns.xml create mode 100644 pkg/test/output/filter_roots.xml diff --git a/cmd/aem/content.go b/cmd/aem/content.go index ca30329b..48490511 100644 --- a/cmd/aem/content.go +++ b/cmd/aem/content.go @@ -6,6 +6,8 @@ import ( "github.com/wttech/aemc/pkg" "github.com/wttech/aemc/pkg/common/pathx" "github.com/wttech/aemc/pkg/content" + "os" + "path/filepath" "strings" ) @@ -74,7 +76,7 @@ func (c *CLI) contentDownloadCmd() *cobra.Command { } pid, _ := cmd.Flags().GetString("pid") targetFile, _ := cmd.Flags().GetString("target-file") - filterRoots, _ := cmd.Flags().GetStringSlice("filter-roots") + filterRoots := determineFilterRoots(cmd) filterFile, _ := cmd.Flags().GetString("filter-file") if err = instance.ContentManager().Download(targetFile, pkg.PackageCreateOpts{ PID: pid, @@ -108,8 +110,6 @@ func (c *CLI) contentPullCmd() *cobra.Command { c.Error(err) return } - clean, _ := cmd.Flags().GetBool("clean") - replace, _ := cmd.Flags().GetBool("replace") dir, err := determineContentDir(cmd) if err != nil { c.Error(err) @@ -120,13 +120,15 @@ func (c *CLI) contentPullCmd() *cobra.Command { c.Error(err) return } + filterRoots := determineFilterRoots(cmd) + filterFile, _ := cmd.Flags().GetString("filter-file") + excludePatterns := determineExcludePatterns(cmd) + clean, _ := cmd.Flags().GetBool("clean") + replace, _ := cmd.Flags().GetBool("replace") if dir != "" { - filterRoots, _ := cmd.Flags().GetStringSlice("filter-roots") - filterFile, _ := cmd.Flags().GetString("filter-file") if err = instance.ContentManager().PullDir(dir, clean, replace, pkg.PackageCreateOpts{ FilterRoots: filterRoots, FilterFile: filterFile, - ContentDir: dir, }); err != nil { c.Error(err) return @@ -134,7 +136,8 @@ func (c *CLI) contentPullCmd() *cobra.Command { c.SetOutput("dir", dir) } else if file != "" { if err = instance.ContentManager().PullFile(file, clean, pkg.PackageCreateOpts{ - ContentFile: file, + FilterRoots: filterRoots, + ExcludePatterns: excludePatterns, }); err != nil { c.Error(err) return @@ -172,7 +175,7 @@ func (c *CLI) contentCopyCmd() *cobra.Command { c.Error(err) return } - filterRoots, _ := cmd.Flags().GetStringSlice("filter-roots") + filterRoots := determineFilterRoots(cmd) filterFile, _ := cmd.Flags().GetString("filter-file") clean, _ := cmd.Flags().GetBool("clean") if err = instance.ContentManager().Copy(targetInstance, clean, pkg.PackageCreateOpts{ @@ -221,7 +224,7 @@ func determineContentDir(cmd *cobra.Command) (string, error) { return "", fmt.Errorf("content path '%s' does not contain '%s'", path, content.JCRRoot) } if path != "" && !pathx.Exists(path) { - return "", fmt.Errorf("content path does not exist: %s", path) + return "", fmt.Errorf("content path '%s' need to exist on file system; consider using 'dir' or 'file' parameter otherwise", path) } if path != "" && pathx.IsDir(path) { return path, nil @@ -239,10 +242,53 @@ func determineContentFile(cmd *cobra.Command) (string, error) { return "", fmt.Errorf("content path '%s' does not contain '%s'", path, content.JCRRoot) } if path != "" && !pathx.Exists(path) { - return "", fmt.Errorf("content path does not exist: %s", path) + return "", fmt.Errorf("content path '%s' need to exist on file system; consider using 'dir' or 'file' parameter otherwise", path) } if path != "" && pathx.IsFile(path) { return path, nil } return file, nil } + +func determineFilterRoots(cmd *cobra.Command) []string { + filterRoots, _ := cmd.Flags().GetStringSlice("filter-roots") + if len(filterRoots) > 0 { + return filterRoots + } + filterFile, _ := cmd.Flags().GetString("filter-file") + if filterFile != "" { + return nil + } + dir, _ := determineContentDir(cmd) + if dir != "" { + return []string{pkg.DetermineFilterRoot(dir)} + } + file, _ := determineContentFile(cmd) + if file != "" { + return []string{pkg.DetermineFilterRoot(file)} + } + return nil +} + +func determineExcludePatterns(cmd *cobra.Command) []string { + file, _ := determineContentFile(cmd) + if file == "" || !strings.HasSuffix(file, content.JCRContentFile) { + return nil + } + + dir := filepath.Dir(file) + entries, err := os.ReadDir(dir) + if err != nil { + return nil + } + + var excludePatterns []string + for _, entry := range entries { + if entry.Name() != content.JCRContentFile { + jcrPath := pkg.DetermineFilterRoot(filepath.Join(dir, entry.Name())) + excludePattern := fmt.Sprintf("%s(/.*)?", jcrPath) + excludePatterns = append(excludePatterns, excludePattern) + } + } + return excludePatterns +} diff --git a/cmd/aem/package.go b/cmd/aem/package.go index 6911ed52..a96d7e23 100644 --- a/cmd/aem/package.go +++ b/cmd/aem/package.go @@ -506,8 +506,7 @@ func (c *CLI) pkgPathByFlags(cmd *cobra.Command) (string, error) { path := c.aem.BaseOpts().TmpDir + "/package/" + fileName if !pathx.Exists(path) { log.Infof("downloading package from URL '%s' to file '%s'", url, path) - err := httpx.DownloadOnce(url, path) - if err != nil { + if err := httpx.DownloadOnce(url, path); err != nil { return "", err } log.Infof("downloaded package from URL '%s' to file '%s'", url, path) @@ -598,8 +597,7 @@ func (c *CLI) pkgUpdateCmd() *cobra.Command { return } filterRoots, _ := cmd.Flags().GetStringSlice("filter-roots") - err = p.UpdateFilters(pkg.NewPackageFilters(filterRoots)) - if err != nil { + if err = p.UpdateFilters(pkg.NewPackageFilters(filterRoots)); err != nil { c.Error(err) return } diff --git a/pkg/common/pathx/pathx.go b/pkg/common/pathx/pathx.go index ac2a3543..00e938f8 100644 --- a/pkg/common/pathx/pathx.go +++ b/pkg/common/pathx/pathx.go @@ -202,10 +202,10 @@ func DirAndFileName(path string) (string, string) { func RandomDir(tmpDir string, prefix string) string { suffix, _ := goutils.RandomNumeric(8) - return filepath.Join(tmpDir, prefix+"_"+suffix) + return Abs(filepath.Join(tmpDir, prefix+"_"+suffix)) } func RandomFileName(tmpDir string, prefix string, extension string) string { suffix, _ := goutils.RandomNumeric(8) - return filepath.Join(tmpDir, prefix+"_"+suffix+extension) + return Abs(filepath.Join(tmpDir, prefix+"_"+suffix+extension)) } diff --git a/pkg/content/content.go b/pkg/content/content.go index f7955a94..fed2f8f8 100644 --- a/pkg/content/content.go +++ b/pkg/content/content.go @@ -9,7 +9,6 @@ import ( "github.com/wttech/aemc/pkg/base" "github.com/wttech/aemc/pkg/common/pathx" "github.com/wttech/aemc/pkg/common/stringsx" - "io" "io/fs" "os" "path/filepath" @@ -18,18 +17,13 @@ import ( ) const ( - JCRRoot = "jcr_root" - JCRContentFile = ".content.xml" - JCRContentFileSuffix = ".xml" - JCRMixinTypesProp = "jcr:mixinTypes" - JCRRootPrefix = " -[[range .FilterRoots]] - [[end]] +[[if .ExcludePatterns]] + [[range .ExcludePatterns]] + [[end]] + [[else]][[range .FilterRoots]] + [[end]][[end]] diff --git a/pkg/test/clear_file_test.go b/pkg/test/clear_file_test.go new file mode 100644 index 00000000..135a43ce --- /dev/null +++ b/pkg/test/clear_file_test.go @@ -0,0 +1,23 @@ +package test + +import ( + "github.com/wttech/aemc/pkg" + "testing" +) + +func TestDetermineCleanFile(t *testing.T) { + tests := []struct { + path, expected string + }{ + {"/somepath/jcr_root/content/my_file.xml", "/somepath/jcr_root/content/my_file.xml"}, + {"/somepath/jcr_root/content/_cq_file.xml", "/somepath/jcr_root/content/_cq_file/.content.xml"}, + {"/somepath/jcr_root/content/_cq_file/.content.xml", "/somepath/jcr_root/content/_cq_file/.content.xml"}, + {"/somepath/jcr_root/content/.content.xml", "/somepath/jcr_root/content/.content.xml"}, + } + for _, test := range tests { + actual := pkg.DetermineCleanFile(test.path) + if actual != test.expected { + t.Errorf("DetermineCleanFile(%s) = %s; want %s", test.path, actual, test.expected) + } + } +} diff --git a/pkg/test/filter_file_test.go b/pkg/test/filter_file_test.go new file mode 100644 index 00000000..30c8c0a3 --- /dev/null +++ b/pkg/test/filter_file_test.go @@ -0,0 +1,39 @@ +package test + +import ( + "github.com/wttech/aemc/pkg/common/tplx" + "github.com/wttech/aemc/pkg/pkg" + "testing" +) + +func testFilterFile(t *testing.T, filterFile string, expectedFile string, data map[string]any) { + bytes, err := pkg.VaultFS.ReadFile(filterFile) + if err != nil { + t.Fatalf("%v %v", bytes, err) + } + expected, err := VaultFS.ReadFile(expectedFile) + if err != nil { + t.Fatalf("%v %v", bytes, err) + } + actual, err := tplx.RenderString(string(bytes), data) + if actual != string(expected) { + t.Errorf("RenderString(%s, %v) = %s; want %s", string(bytes), data, actual, expected) + } +} + +func TestFilterRoots(t *testing.T) { + testFilterFile(t, "vault/META-INF/vault/filter.xml", "output/filter_roots.xml", + map[string]any{ + "FilterRoots": []string{"/apps/my_site", "/content/my_site"}, + }, + ) +} + +func TestExcludePatterns(t *testing.T) { + testFilterFile(t, "vault/META-INF/vault/filter.xml", "output/exclude_patterns.xml", + map[string]any{ + "FilterRoots": []string{"/apps/my_site", "/content/my_site"}, + "ExcludePatterns": []string{"/apps/my_site/cq:dialog(/.*)?", "/apps/my_site/rep:policy(/.*)?"}, + }, + ) +} diff --git a/pkg/test/filter_root_test.go b/pkg/test/filter_root_test.go new file mode 100644 index 00000000..922a8764 --- /dev/null +++ b/pkg/test/filter_root_test.go @@ -0,0 +1,37 @@ +package test + +import ( + "github.com/wttech/aemc/pkg" + "testing" +) + +func TestDetermineFilterRoot(t *testing.T) { + tests := []struct { + path, expected string + }{ + {"/somepath/jcr_root/content/my_site", "/content/my_site"}, + {"/somepath/jcr_root/content/my_site/_cq_path", "/content/my_site/cq:path"}, + {"/somepath/jcr_root/content/my_site/_xmpBJ_path", "/content/my_site/xmpBJ:path"}, + {"/somepath/jcr_root/content/my_site/_s7sitecatalyst_path", "/content/my_site/s7sitecatalyst:path"}, + {"/somepath/jcr_root/content/my_site/adobe_dam%3apath", "/content/my_site/adobe_dam:path"}, + {"/somepath/jcr_root/content/my_site/_cq__sub_path_", "/content/my_site/cq:_sub_path_"}, + {"/somepath/jcr_root/content/my_site/__cq_path", "/content/my_site/_cq_path"}, + {"/somepath/jcr_root/content/my_site/__abc_path", "/content/my_site/_abc_path"}, + {"/somepath/jcr_root/content/my_site/__path", "/content/my_site/_path"}, + {"/somepath/jcr_root/content/my_site/___path", "/content/my_site/__path"}, + {"\\somepath\\jcr_root\\content\\my_site", "/content/my_site"}, + {"\\somepath\\jcr_root\\content\\my_site\\_cq_path", "/content/my_site/cq:path"}, + {"/somepath/jcr_root/content/my_app/_cq_dialog/.content.xml", "/content/my_app/cq:dialog"}, + {"/somepath/jcr_root/content/my_app/_cq_dialog.xml", "/content/my_app/cq:dialog"}, + {"/somepath/jcr_root/content/my_conf/workflow.xml", "/content/my_conf/workflow"}, + {"/somepath/jcr_root/content/dam/my_site/image.png", "/content/dam/my_site/image.png"}, + {"/somepath/jcr_root/conf/my_site/_sling_configs/com.config.ImageConfig", "/conf/my_site/sling:configs/com.config.ImageConfig"}, + {"/somepath/jcr_root/conf/my_site/_sling_configs/com.config.ImageConfig/_jcr_content", "/conf/my_site/sling:configs/com.config.ImageConfig/jcr:content"}, + } + for _, test := range tests { + actual := pkg.DetermineFilterRoot(test.path) + if actual != test.expected { + t.Errorf("DetermineFilterRoot(%s) = %s; want %s", test.path, actual, test.expected) + } + } +} diff --git a/pkg/test/output.go b/pkg/test/output.go new file mode 100644 index 00000000..56a834e2 --- /dev/null +++ b/pkg/test/output.go @@ -0,0 +1,6 @@ +package test + +import "embed" + +//go:embed output +var VaultFS embed.FS diff --git a/pkg/test/output/exclude_patterns.xml b/pkg/test/output/exclude_patterns.xml new file mode 100644 index 00000000..aa4ae2bb --- /dev/null +++ b/pkg/test/output/exclude_patterns.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/pkg/test/output/filter_roots.xml b/pkg/test/output/filter_roots.xml new file mode 100644 index 00000000..1c5aca1b --- /dev/null +++ b/pkg/test/output/filter_roots.xml @@ -0,0 +1,5 @@ + + + + +