07bde59d75e486a4a353578d34f74aef3debbdbb
[teamcity/dotNetPackagesSupport.git] / nuget-agent / src / jetbrains / buildServer / nuget / agent / runner / publish / fsScanner / DirectoryScanner.java
1 /*\r
2  * Copyright 2000-2011 JetBrains s.r.o.\r
3  *\r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  *\r
8  * http://www.apache.org/licenses/LICENSE-2.0\r
9  *\r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  */\r
16 package jetbrains.buildServer.nuget.agent.runner.publish.fsScanner;\r
17 \r
18 import com.intellij.openapi.diagnostic.Logger;\r
19 import org.jetbrains.annotations.NotNull;\r
20 \r
21 import java.io.File;\r
22 import java.util.ArrayList;\r
23 import java.util.Collection;\r
24 import java.util.Collections;\r
25 import java.util.List;\r
26 \r
27 /// <summary>\r
28 /// Nant-syntax wildcard matcher on file system trees\r
29 /// </summary>\r
30 public class DirectoryScanner {\r
31   private static final Logger LOG = Logger.getInstance(DirectoryScanner.class.getName());\r
32 \r
33   public static Collection<File> FindFiles(@NotNull File root, String[] includes, String[] excludes) {\r
34     return FindFiles(new RealFileSystem(), new RealDirectoryEntry(new FileSystemPath(root)), includes, excludes);\r
35   }\r
36 \r
37   private static Collection<File> FindFiles(IFileSystem fs, IDirectoryEntry root, String[] includes, String[] excludes) {\r
38     List<Wildcard> basePath = BuildSearchPrefix(root, fs.CaseSensitive());\r
39 \r
40     List<FileSystemPath> result = new ArrayList<FileSystemPath>();\r
41     FindFilesRec(\r
42             fs.Root(),\r
43             result,\r
44             ToAntPatternState(fs, basePath, fs.CaseSensitive(), includes),\r
45             ToAntPatternState(fs, basePath, fs.CaseSensitive(), excludes)\r
46     );\r
47 \r
48     List<File> foundFiles = new ArrayList<File>();\r
49     for (FileSystemPath path : result) {\r
50       foundFiles.add(path.FilePath());\r
51     }\r
52     return foundFiles;\r
53   }\r
54 \r
55   private static List<Wildcard> BuildSearchPrefix(@NotNull IDirectoryEntry root, boolean caseSensitive) {\r
56     List<Wildcard> wildcardPrefix = new ArrayList<Wildcard>();\r
57     while (root.Parent() != null) {\r
58       wildcardPrefix.add(new Wildcard(root.Name(), caseSensitive));\r
59       root = root.Parent();\r
60     }\r
61     Collections.reverse(wildcardPrefix);\r
62 \r
63     return wildcardPrefix;\r
64   }\r
65 \r
66   private static List<AntPatternState> ToAntPatternState(IFileSystem fs, List<Wildcard> wildcardPrefix, boolean caseSensitive, String[] patterns) {\r
67     List<AntPatternState> result = new ArrayList<AntPatternState>();\r
68     for (String x : patterns) {\r
69       result.add(new AntPatternState(ParsePattern(fs, wildcardPrefix, caseSensitive, x)));\r
70     }\r
71     return result;\r
72   }\r
73 \r
74   private static List<Wildcard> ParsePattern(IFileSystem fs, List<Wildcard> rootPrefix, boolean caseSensitive, String pattern) {\r
75     List<Wildcard> wildcards = AntPatternUtil.ParsePattern(pattern, caseSensitive);\r
76 \r
77     if (fs.IsPathAbsolute(pattern))\r
78       return wildcards;\r
79 \r
80     List<Wildcard> result = new ArrayList<Wildcard>();\r
81     result.addAll(rootPrefix);\r
82     result.addAll(wildcards);\r
83 \r
84     return result;\r
85   }\r
86 \r
87   private interface AnyPredicate {\r
88     boolean matches(AntPatternState.MatchResult r);\r
89   }\r
90 \r
91   private static boolean Any(List<AntPatternState> state, String component, AnyPredicate predicate, List<AntPatternState> newState) {\r
92     boolean any = false;\r
93 \r
94     for (int i = 0; i < state.size(); i++) {\r
95       final AntPatternState.AntPatternStateMatch enter = state.get(i).Enter(component);\r
96       AntPatternState.MatchResult match = enter.getResult();\r
97       newState.add(i, enter.getState());\r
98 \r
99       if (predicate.matches(match))\r
100         any = true;\r
101     }\r
102 \r
103     return any;\r
104   }\r
105 \r
106   private static void FindFilesRec(IDirectoryEntry directory, List<FileSystemPath> result, List<AntPatternState> includeState, List<AntPatternState> excludeState) {\r
107     LOG.debug("Scanning directory: " + directory.Name());\r
108     for (IFileEntry file : directory.Files()) {\r
109       List<AntPatternState> newState = new ArrayList<AntPatternState>();\r
110 \r
111       if (!Any(includeState, file.Name(), AntPredicateImpl.Predicate(false, AntPatternState.MatchResult.YES), newState))\r
112         continue;\r
113 \r
114       newState.clear();\r
115       if (Any(excludeState, file.Name(), AntPredicateImpl.Predicate(false, AntPatternState.MatchResult.YES), newState))\r
116         continue;\r
117 \r
118       result.add(file.Path());\r
119     }\r
120 \r
121     for (IDirectoryEntry subEntry : directory.Subdirectories()) {\r
122       String name = subEntry.Name();\r
123 \r
124       List<AntPatternState> newIncludeState = new ArrayList<AntPatternState>();\r
125       if (!Any(includeState, name, AntPredicateImpl.Predicate(true, AntPatternState.MatchResult.NO), newIncludeState))\r
126         continue;\r
127 \r
128       List<AntPatternState> newExcludeState = new ArrayList<AntPatternState>();\r
129       if (Any(excludeState, name, AntPredicateImpl.Predicate(false, AntPatternState.MatchResult.YES), newExcludeState))\r
130         continue;\r
131 \r
132       FindFilesRec(subEntry, result, newIncludeState, newExcludeState);\r
133     }\r
134   }\r
135 \r
136   private static class AntPredicateImpl {\r
137     private final boolean myNegatiate;\r
138     private final AntPatternState.MatchResult myResult;\r
139 \r
140     private AntPredicateImpl(boolean negatiate, AntPatternState.MatchResult result) {\r
141       myNegatiate = negatiate;\r
142       myResult = result;\r
143     }\r
144 \r
145     private boolean AnyPredicateImpl(AntPatternState.MatchResult r) {\r
146       return myNegatiate ? myResult != r : myResult == r;\r
147     }\r
148 \r
149 \r
150     public static AnyPredicate Predicate(boolean not, AntPatternState.MatchResult state) {\r
151       final AntPredicateImpl antPredicate = new AntPredicateImpl(not, state);\r
152       return new AnyPredicate() {\r
153         public boolean matches(AntPatternState.MatchResult r) {\r
154           return antPredicate.AnyPredicateImpl(r);\r
155         }\r
156       };\r
157     }\r
158   }\r
159 }\r