diff --git a/pkg/sync/sync.go b/pkg/sync/sync.go index 10546ea1511..e29a3457d03 100644 --- a/pkg/sync/sync.go +++ b/pkg/sync/sync.go @@ -9,6 +9,7 @@ import ( "github.com/devfile/library/v2/pkg/devfile/generator" dfutil "github.com/devfile/library/v2/pkg/util" + gitignore "github.com/sabhiram/go-gitignore" "github.com/redhat-developer/odo/pkg/exec" "github.com/redhat-developer/odo/pkg/platform" @@ -93,7 +94,6 @@ func (a SyncClient) SyncFiles(ctx context.Context, syncParameters SyncParameters // Calculate the files to sync // Tries to sync the deltas unless it is a forced push // if it is a forced push (ForcePush) reset the index to do a full sync - absIgnoreRules := dfutil.GetAbsGlobExps(syncParameters.Path, syncParameters.IgnoredFiles) // Before running the indexer, make sure the .odo folder exists (or else the index file will not get created) odoFolder := filepath.Join(syncParameters.Path, ".odo") @@ -128,7 +128,10 @@ func (a SyncClient) SyncFiles(ctx context.Context, syncParameters SyncParameters // apply the glob rules from the .gitignore/.odoignore file // and ignore the files on which the rules apply and filter them out - filesChangedFiltered, filesDeletedFiltered := dfutil.FilterIgnores(ret.FilesChanged, ret.FilesDeleted, absIgnoreRules) + filesChangedFiltered, filesDeletedFiltered, err := filterIgnores(syncParameters.Path, ret.FilesChanged, ret.FilesDeleted, syncParameters.IgnoredFiles) + if err != nil { + return false, err + } deletedFiles = append(filesDeletedFiltered, ret.RemoteDeleted...) deletedFiles = append(deletedFiles, ret.RemoteDeleted...) @@ -159,6 +162,32 @@ func (a SyncClient) SyncFiles(ctx context.Context, syncParameters SyncParameters return true, nil } +// filterIgnores applies the gitignore rules on the filesChanged and filesDeleted and filters them +// returns the filtered results which match any of the gitignore rules +func filterIgnores(path string, filesChanged, filesDeleted, absIgnoreRules []string) (filesChangedFiltered, filesDeletedFiltered []string, err error) { + ignoreMatcher := gitignore.CompileIgnoreLines(absIgnoreRules...) + for _, file := range filesChanged { + // filesChanged are absoute paths + rel, err := filepath.Rel(path, file) + if err != nil { + return nil, nil, fmt.Errorf("path=%q, file=%q, %w", path, file, err) + } + match := ignoreMatcher.MatchesPath(rel) + if !match { + filesChangedFiltered = append(filesChangedFiltered, file) + } + } + + for _, file := range filesDeleted { + // filesDeleted are relative paths + match := ignoreMatcher.MatchesPath(file) + if !match { + filesDeletedFiltered = append(filesDeletedFiltered, file) + } + } + return filesChangedFiltered, filesDeletedFiltered, nil +} + // pushLocal syncs source code from the user's disk to the component func (a SyncClient) pushLocal(ctx context.Context, path string, files []string, delFiles []string, isForcePush bool, globExps []string, compInfo ComponentInfo, ret util.IndexerRet) error { klog.V(4).Infof("Push: componentName: %s, path: %s, files: %s, delFiles: %s, isForcePush: %+v", compInfo.ComponentName, path, files, delFiles, isForcePush) diff --git a/tests/integration/cmd_dev_test.go b/tests/integration/cmd_dev_test.go index d6c4b213660..404b6c10cca 100644 --- a/tests/integration/cmd_dev_test.go +++ b/tests/integration/cmd_dev_test.go @@ -1569,7 +1569,7 @@ ComponentSettings: }) When("adding local files to gitignore and running odo dev", func() { - var gitignorePath, newDirPath, newFilePath1, newFilePath2, newFilePath3, stdOut, podName string + var gitignorePath, newDirPath, newFilePath1, newFilePath2, newFilePath3, newFilePath4, newFilePath5, stdOut, podName string var session helper.DevSession var devfileCmpName string BeforeEach(func() { @@ -1579,6 +1579,8 @@ ComponentSettings: newDirPath = filepath.Join(commonVar.Context, "testdir") newFilePath2 = filepath.Join(newDirPath, "foobar.txt") newFilePath3 = filepath.Join(newDirPath, "baz.txt") + newFilePath4 = filepath.Join(newDirPath, "ignore.css") + newFilePath5 = filepath.Join(newDirPath, "main.css") helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context) helper.CopyExampleDevFile( filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), @@ -1598,7 +1600,15 @@ ComponentSettings: if err := helper.CreateFileWithContent(newFilePath3, "hello world"); err != nil { fmt.Printf("the foobar.txt file was not created, reason %v", err.Error()) } - if err := helper.CreateFileWithContent(gitignorePath, "foobar.txt"); err != nil { + if err := helper.CreateFileWithContent(newFilePath4, "div {}"); err != nil { + fmt.Printf("the %s file was not created, reason %v", newFilePath4, err.Error()) + } + if err := helper.CreateFileWithContent(newFilePath5, "div {}"); err != nil { + fmt.Printf("the %s file was not created, reason %v", newFilePath5, err.Error()) + } + if err := helper.CreateFileWithContent(gitignorePath, `foobar.txt +*.css +!main.css`); err != nil { fmt.Printf("the .gitignore file was not created, reason %v", err.Error()) } var err error @@ -1617,6 +1627,8 @@ ComponentSettings: stdOut = commonVar.CliRunner.ExecListDir(podName, commonVar.Project, "/projects/testdir") helper.MatchAllInOutput(stdOut, []string{"baz.txt"}) helper.DontMatchAllInOutput(stdOut, []string{"foobar.txt"}) + helper.MatchAllInOutput(stdOut, []string{"main.css"}) + helper.DontMatchAllInOutput(stdOut, []string{"ignore.css"}) } It("should not sync ignored files to the container", func() {