/
NameFilter.scala
155 lines (124 loc) · 6.26 KB
/
NameFilter.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/* sbt
* Copyright 2009-2015 Typesafe, Inc, Mark Harrah, and others
*/
package sbt.io
import java.io.File
import java.util.regex.Pattern
import scala.language.implicitConversions
/** A `java.io.FileFilter` with additional methods for combining filters. */
trait FileFilter extends java.io.FileFilter {
/** Constructs a filter that accepts a `File` if it matches either this filter or the given `filter`. */
def ||(filter: FileFilter): FileFilter =
new SimpleFileFilter(file => accept(file) || filter.accept(file)) {
override def toString = s"SimpleFileFilter(${FileFilter.this} || $filter)"
}
/** Constructs a filter that accepts a `File` if it matches both this filter and the given `filter`. */
def &&(filter: FileFilter): FileFilter =
new SimpleFileFilter(file => accept(file) && filter.accept(file)) {
override def toString = s"SimpleFileFilter(${FileFilter.this} && $filter)"
}
/** Constructs a filter that accepts a `File` if it matches this filter but does not match the given `filter`. */
def --(filter: FileFilter): FileFilter =
new SimpleFileFilter(file => accept(file) && !filter.accept(file)) {
override def toString = s"SimpleFileFilter(${FileFilter.this} -- $filter)"
}
/** Constructs a filter that accepts a `File` if it does not match this filter. */
def unary_- : FileFilter = new SimpleFileFilter(file => !accept(file)) {
override def toString = s"SimpleFileFilter(-${FileFilter.this})"
}
}
/** A filter on Strings. This also functions as a [[FileFilter]] by applying the String filter to the value of a File's `getName`. */
trait NameFilter extends FileFilter {
/** Returns `true` to include the `name`, `false` to exclude it. */
def accept(name: String): Boolean
/** Accepts `File` if its `getName` method is accepted by this filter. */
final def accept(file: File): Boolean = accept(file.getName)
/** Constructs a filter that accepts a `String` if it matches either this filter or the given `filter`. */
def |(filter: NameFilter): NameFilter =
new SimpleFilter(name => accept(name) || filter.accept(name)) {
override def toString = s"SimpleFilter(${NameFilter.this} | $filter)"
}
/** Constructs a filter that accepts a `String` if it matches both this filter and the given `filter`. */
def &(filter: NameFilter): NameFilter =
new SimpleFilter(name => accept(name) && filter.accept(name)) {
override def toString = s"SimpleFilter(${NameFilter.this} & $filter)"
}
/** Constructs a filter that accepts a `String` if it matches this filter but not the given `filter`. */
def -(filter: NameFilter): NameFilter =
new SimpleFilter(name => accept(name) && !filter.accept(name)) {
override def toString = s"SimpleFilter(${NameFilter.this} - $filter)"
}
/** Constructs a filter that accepts a `String` if it does not match this filter. */
override def unary_- : NameFilter = new SimpleFilter(name => !accept(name)) {
override def toString = s"SimpleFilter(-${NameFilter.this})"
}
}
/** A [[FileFilter]] that selects files that are hidden according to `java.io.File.isHidden` or if they start with a dot (`.`). */
object HiddenFileFilter extends FileFilter {
def accept(file: File) = file.isHidden && file.getName != "."
}
/** A [[FileFilter]] that selects files that exist according to `java.io.File.exists`. */
object ExistsFileFilter extends FileFilter {
def accept(file: File) = file.exists
}
/** A [[FileFilter]] that selects files that are a directory according to `java.io.File.isDirectory`. */
object DirectoryFilter extends FileFilter {
def accept(file: File) = file.isDirectory
}
/** A [[FileFilter]] that selects files according the predicate `acceptFunction`. */
sealed class SimpleFileFilter(val acceptFunction: File => Boolean) extends FileFilter {
final def accept(file: File) = acceptFunction(file)
}
/** A [[NameFilter]] that accepts a name if it is exactly equal to `matchName`. */
final class ExactFilter(val matchName: String) extends NameFilter {
def accept(name: String) = matchName == name
override def toString = s"ExactFilter($matchName)"
}
/** A [[NameFilter]] that accepts a name if the predicate `acceptFunction` accepts it. */
sealed class SimpleFilter(val acceptFunction: String => Boolean) extends NameFilter {
final def accept(name: String) = acceptFunction(name)
}
/** A [[NameFilter]] that accepts a name if it matches the regular expression defined by `pattern`. */
final class PatternFilter(val pattern: Pattern) extends NameFilter {
def accept(name: String) = pattern.matcher(name).matches
override def toString = s"PatternFilter($pattern)"
}
/** A [[NameFilter]] that accepts all names. That is, `accept` always returns `true`. */
object AllPassFilter extends NameFilter {
def accept(name: String) = true
}
/** A [[NameFilter]] that accepts nothing. That is, `accept` always returns `false`. */
object NothingFilter extends NameFilter {
def accept(name: String) = false
}
object NameFilter {
implicit def fnToNameFilter(f: String => Boolean): NameFilter = new NameFilter {
def accept(name: String) = f(name)
}
}
object FileFilter {
/** Allows a String to be used where a `NameFilter` is expected and any asterisks (`*`) will be interpreted as wildcards. See [[sbt.io.GlobFilter]].*/
implicit def globFilter(s: String): NameFilter = GlobFilter(s)
}
/** Constructs a filter from a String, interpreting wildcards. See the [[GlobFilter.apply]] method. */
object GlobFilter {
/**
* Constructs a [[NameFilter]] from a String, interpreting `*` as a wildcard.
* Control characters, as determined by `java.lang.Character.isISOControl` are not allowed
* due to the implementation restriction of using Java's `Pattern` and `Pattern.quote`,
* which do not handle these characters.
*/
def apply(expression: String): NameFilter = {
require(
!expression.exists(java.lang.Character.isISOControl),
"Control characters not allowed in filter expression."
)
if (expression == "*")
AllPassFilter
else if (expression.indexOf('*') < 0) // includes case where expression is empty
new ExactFilter(expression)
else
new PatternFilter(Pattern.compile(expression.split("\\*", -1).map(quote).mkString(".*")))
}
private def quote(s: String) = if (s.isEmpty) "" else Pattern.quote(s.replaceAll("\n", """\n"""))
}