1818
1919import com .google .common .base .Preconditions ;
2020import com .google .common .base .Splitter ;
21+ import com .google .common .collect .HashMultimap ;
2122import com .google .common .collect .ImmutableList ;
23+ import com .google .common .collect .SetMultimap ;
24+ import com .google .common .collect .Sets ;
2225import com .google .copybara .exception .RepoException ;
2326import com .google .copybara .util .console .Console ;
2427import java .io .IOException ;
3033import java .nio .file .attribute .BasicFileAttributes ;
3134import java .util .ArrayList ;
3235import java .util .List ;
36+ import java .util .Set ;
3337
3438/**
3539 * A walker which adds all files not matching a glob to the index of a Git repo using {@code git
@@ -69,12 +73,12 @@ void findSubmodules(Console console) throws RepoException {
6973 * Adds all the excluded files and submodules.
7074 */
7175 void add () throws RepoException , IOException {
72- ExcludesFinder visitor = new ExcludesFinder (repo .getGitDir (), pathMatcher );
76+ ExcludesFinder visitor = new ExcludesFinder (repo .getGitDir (), pathMatcher , repo . getWorkTree () );
7377 Files .walkFileTree (repo .getWorkTree (), visitor );
7478
7579 int size = 0 ;
7680 List <String > current = new ArrayList <>();
77- for (String path : visitor .excluded ) {
81+ for (String path : visitor .excludedFiles . values () ) {
7882 current .add (path );
7983 size += path .length ();
8084 // Split the executions in chunks of 6K. 8K triggers arg max in some systems, so
@@ -99,11 +103,14 @@ private static final class ExcludesFinder extends SimpleFileVisitor<Path> {
99103
100104 private final Path gitDir ;
101105 private final PathMatcher destinationFiles ;
102- private final List <String > excluded = new ArrayList <>();
106+ private final Path root ;
107+ private final SetMultimap <Path , String > excludedFiles = HashMultimap .create ();
108+ private final Set <Path > someMatchInDir = Sets .newHashSet ();
103109
104- private ExcludesFinder (Path gitDir , PathMatcher destinationFiles ) {
110+ private ExcludesFinder (Path gitDir , PathMatcher destinationFiles , Path root ) {
105111 this .gitDir = gitDir ;
106112 this .destinationFiles = destinationFiles ;
113+ this .root = root ;
107114 }
108115
109116 @ Override
@@ -117,11 +124,30 @@ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
117124
118125 @ Override
119126 public FileVisitResult visitFile (Path file , BasicFileAttributes attrs ) throws IOException {
120- if (!destinationFiles .matches (file )) {
121- excluded .add (file .toString ());
127+ if (destinationFiles .matches (file )) {
128+ // Tell parent dir that one of its children is affected
129+ someMatchInDir .add (file .getParent ());
130+ } else {
131+ excludedFiles .put (file .getParent (), file .toString ());
132+ if (Files .isHidden (file )) {
133+ // Dir is not affected but 'git add dir' doesn't work for 'dir/.file'.
134+ someMatchInDir .add (file .getParent ());
135+ }
122136 }
123137 return FileVisitResult .CONTINUE ;
124138 }
125139
140+ @ Override
141+ public FileVisitResult postVisitDirectory (Path dir , IOException exc ) throws IOException {
142+ if (someMatchInDir .contains (dir )) {
143+ // Tell parent dir that one of its children is affected
144+ someMatchInDir .add (dir .getParent ());
145+ } else if (!root .equals (dir )) {
146+ // If everything inside the dir is affected, replace it with the folder itself
147+ excludedFiles .removeAll (dir );
148+ excludedFiles .put (dir .getParent (), dir .toString ());
149+ }
150+ return super .postVisitDirectory (dir , exc );
151+ }
126152 }
127153}
0 commit comments