14
14
15
15
package com .google .devtools .build .lib .skyframe ;
16
16
17
+ import com .google .common .annotations .VisibleForTesting ;
17
18
import com .google .common .base .Function ;
18
19
import com .google .common .collect .ImmutableList ;
20
+ import com .google .common .collect .ImmutableSet ;
19
21
import com .google .common .collect .Iterables ;
20
22
import com .google .devtools .build .lib .util .OS ;
21
23
import com .google .devtools .build .lib .util .Preconditions ;
22
24
import com .google .devtools .build .lib .vfs .ModifiedFileSet ;
23
25
import com .google .devtools .build .lib .vfs .PathFragment ;
24
-
26
+ import com .google .devtools .common .options .Option ;
27
+ import com .google .devtools .common .options .OptionsBase ;
25
28
import java .io .IOException ;
26
29
import java .nio .file .FileSystems ;
27
30
import java .nio .file .Path ;
28
- import java .nio .file .WatchService ;
29
31
import java .util .Set ;
30
32
31
33
/**
38
40
* {@link WatchServiceDiffAwareness}.
39
41
*/
40
42
public abstract class LocalDiffAwareness implements DiffAwareness {
43
+ /**
44
+ * Option to enable / disable local diff awareness.
45
+ */
46
+ public static final class Options extends OptionsBase {
47
+ @ Option (
48
+ name = "watchfs" ,
49
+ defaultValue = "false" ,
50
+ category = "server startup" ,
51
+ help = "If true, %{product} tries to use the operating system's file watch service for "
52
+ + "local changes instead of scanning every file for a change."
53
+ )
54
+ public boolean watchFS ;
55
+ }
41
56
42
57
/** Factory for creating {@link LocalDiffAwareness} instances. */
43
58
public static class Factory implements DiffAwareness .Factory {
@@ -73,16 +88,26 @@ public DiffAwareness maybeCreate(com.google.devtools.build.lib.vfs.Path pathEntr
73
88
return new MacOSXFsEventsDiffAwareness (resolvedPathEntryFragment .toString ());
74
89
}
75
90
76
- WatchService watchService ;
77
- try {
78
- watchService = FileSystems .getDefault ().newWatchService ();
79
- } catch (IOException e ) {
80
- return null ;
81
- }
82
- return new WatchServiceDiffAwareness (resolvedPathEntryFragment .toString (), watchService );
91
+ return new WatchServiceDiffAwareness (resolvedPathEntryFragment .toString ());
83
92
}
84
93
}
85
94
95
+ /**
96
+ * A view that results in any subsequent getDiff calls returning
97
+ * {@link ModifiedFileSet#EVERYTHING_MODIFIED}. Use this if --watchFs is disabled.
98
+ *
99
+ * <p>The position is set to -2 in order for {@link #areInSequence} below to always return false
100
+ * if this view is passed to it. Any negative number would work; we don't use -1 as the other
101
+ * view may have a position of 0.
102
+ */
103
+ protected static final View EVERYTHING_MODIFIED =
104
+ new SequentialView (/*owner=*/ null , /*position=*/ -2 , ImmutableSet .<Path >of ());
105
+
106
+ public static boolean areInSequence (SequentialView oldView , SequentialView newView ) {
107
+ // Keep this in sync with the EVERYTHING_MODIFIED View above.
108
+ return oldView .owner == newView .owner && (oldView .position + 1 ) == newView .position ;
109
+ }
110
+
86
111
private int numGetCurrentViewCalls = 0 ;
87
112
88
113
/** Root directory to watch. This is an absolute path. */
@@ -96,7 +121,8 @@ protected LocalDiffAwareness(String watchRoot) {
96
121
* The WatchService is inherently sequential and side-effectful, so we enforce this by only
97
122
* supporting {@link #getDiff} calls that happen to be sequential.
98
123
*/
99
- private static class SequentialView implements DiffAwareness .View {
124
+ @ VisibleForTesting
125
+ static class SequentialView implements DiffAwareness .View {
100
126
private final LocalDiffAwareness owner ;
101
127
private final int position ;
102
128
private final Set <Path > modifiedAbsolutePaths ;
@@ -107,10 +133,6 @@ public SequentialView(LocalDiffAwareness owner, int position, Set<Path> modified
107
133
this .modifiedAbsolutePaths = modifiedAbsolutePaths ;
108
134
}
109
135
110
- public static boolean areInSequence (SequentialView oldView , SequentialView newView ) {
111
- return oldView .owner == newView .owner && (oldView .position + 1 ) == newView .position ;
112
- }
113
-
114
136
@ Override
115
137
public String toString () {
116
138
return String .format ("SequentialView[owner=%s, position=%d, modifiedAbsolutePaths=%s]" , owner ,
@@ -119,7 +141,7 @@ public String toString() {
119
141
}
120
142
121
143
/**
122
- * Returns true on any call before first call to {@link #newView(Set<Path>) }.
144
+ * Returns true on any call before first call to {@link #newView}.
123
145
*/
124
146
protected boolean isFirstCall () {
125
147
return numGetCurrentViewCalls == 0 ;
@@ -129,8 +151,7 @@ protected boolean isFirstCall() {
129
151
* Create a new views using a list of modified absolute paths. This will increase the view
130
152
* counter.
131
153
*/
132
- protected SequentialView newView (Set <Path > modifiedAbsolutePaths )
133
- throws BrokenDiffAwarenessException {
154
+ protected SequentialView newView (Set <Path > modifiedAbsolutePaths ) {
134
155
numGetCurrentViewCalls ++;
135
156
return new SequentialView (this , numGetCurrentViewCalls , modifiedAbsolutePaths );
136
157
}
@@ -146,7 +167,7 @@ public ModifiedFileSet getDiff(View oldView, View newView)
146
167
} catch (ClassCastException e ) {
147
168
throw new IncompatibleViewException ("Given views are not from LocalDiffAwareness" );
148
169
}
149
- if (!SequentialView . areInSequence (oldSequentialView , newSequentialView )) {
170
+ if (!areInSequence (oldSequentialView , newSequentialView )) {
150
171
return ModifiedFileSet .EVERYTHING_MODIFIED ;
151
172
}
152
173
return ModifiedFileSet .builder ()
0 commit comments