aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Klaus Aehlig <aehlig@google.com>2016-05-27 11:42:32 +0000
committerGravatar Dmitry Lomov <dslomov@google.com>2016-05-30 09:17:25 +0000
commitc6fd6bb3caa78518fbb9148d81efecdee540c29a (patch)
tree2b7cd0063ad4da4b4fe6c0c633e9e5fc45ac7534 /src
parent2fba42e27ec517a8819236d15e45a42bfd5c1823 (diff)
experimental UI: track touched packages during loading/analysis
To give a better understanding of which packages are on the critical path during loading and analysis, provide information in the same way as during execution: show the earliest started, but not yet completed package. As not all packages looked at during the analysis phase are reported to the progress receiver, use a custom class to aggregate those data. -- Change-Id: I03c25efdecb4124e1bc06fce8be9175dc56b5500 Reviewed-on: https://bazel-review.googlesource.com/#/c/3700 MOS_MIGRATED_REVID=123408689
Diffstat (limited to 'src')
-rw-r--r--src/main/java/com/google/devtools/build/lib/runtime/ExperimentalStateTracker.java41
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/LoadingPhaseStartedEvent.java18
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java30
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/PackageProgressReceiver.java73
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java13
-rw-r--r--src/test/java/com/google/devtools/build/lib/runtime/ExperimentalStateTrackerTest.java32
-rw-r--r--src/test/java/com/google/devtools/build/lib/skyframe/PackageProgressReceiverTest.java77
-rwxr-xr-xsrc/test/shell/integration/experimental_ui_test.sh2
8 files changed, 244 insertions, 42 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/ExperimentalStateTracker.java b/src/main/java/com/google/devtools/build/lib/runtime/ExperimentalStateTracker.java
index 769260a2e6..44e38f08b4 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/ExperimentalStateTracker.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/ExperimentalStateTracker.java
@@ -26,8 +26,9 @@ import com.google.devtools.build.lib.buildtool.buildevent.TestFilteringCompleteE
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.pkgcache.LoadingPhaseCompleteEvent;
import com.google.devtools.build.lib.skyframe.LoadingPhaseStartedEvent;
-import com.google.devtools.build.lib.skyframe.LoadingProgressReceiver;
+import com.google.devtools.build.lib.skyframe.PackageProgressReceiver;
import com.google.devtools.build.lib.util.Clock;
+import com.google.devtools.build.lib.util.Pair;
import com.google.devtools.build.lib.util.io.AnsiTerminalWriter;
import com.google.devtools.build.lib.util.io.PositionAwareAnsiTerminalWriter;
import com.google.devtools.build.lib.view.test.TestStatus.BlazeTestStatus;
@@ -40,7 +41,6 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
-import java.util.concurrent.atomic.AtomicInteger;
/**
* An experimental state tracker for the new experimental UI.
@@ -83,8 +83,7 @@ class ExperimentalStateTracker {
private boolean ok;
private ExecutionProgressReceiver executionProgressReceiver;
- private LoadingProgressReceiver loadingProgressReceiver;
- private AtomicInteger numPackagesLoaded;
+ private PackageProgressReceiver packageProgressReceiver;
ExperimentalStateTracker(Clock clock, int targetWidth) {
this.runningActions = new ArrayDeque<>();
@@ -107,12 +106,10 @@ class ExperimentalStateTracker {
void loadingStarted(LoadingPhaseStartedEvent event) {
status = null;
- loadingProgressReceiver = event.getLoadingProgressReceiver();
- numPackagesLoaded = event.getNumPackagesLoaded();
+ packageProgressReceiver = event.getPackageProgressReceiver();
}
void loadingComplete(LoadingPhaseCompleteEvent event) {
- loadingProgressReceiver = null;
int count = event.getTargets().size();
status = "Analyzing";
if (count == 1) {
@@ -124,7 +121,7 @@ class ExperimentalStateTracker {
void analysisComplete(AnalysisPhaseCompleteEvent event) {
status = null;
- numPackagesLoaded = null;
+ packageProgressReceiver = null;
}
void progressReceiverAvailable(ExecutionProgressReceiverAvailableEvent event) {
@@ -388,7 +385,7 @@ class ExperimentalStateTracker {
* bar shows time information relative to the current time.
*/
boolean progressBarTimeDependent() {
- if (numPackagesLoaded != null) {
+ if (packageProgressReceiver != null) {
return true;
}
if (status != null) {
@@ -397,12 +394,6 @@ class ExperimentalStateTracker {
if (runningActions.size() >= 1) {
return true;
}
- if (loadingProgressReceiver != null) {
- // This is kind-of a hack: since the event handler does not get informed about updates
- // in the loading phase, indicate that the progress bar might change even though no
- // explicit update event is known to the event handler.
- return true;
- }
return false;
}
@@ -441,17 +432,21 @@ class ExperimentalStateTracker {
terminalWriter.failStatus();
}
terminalWriter.append(status + ":").normal().append(" " + additionalMessage);
- if (numPackagesLoaded != null) {
- terminalWriter.append(" (" + numPackagesLoaded.get() + " packages loaded)");
+ if (packageProgressReceiver != null) {
+ Pair<String, String> progress = packageProgressReceiver.progressState();
+ terminalWriter.append(" (" + progress.getFirst() + ")");
+ if (progress.getSecond().length() > 0) {
+ terminalWriter.newline().append(" " + progress.getSecond());
+ }
}
return;
}
- if (loadingProgressReceiver != null) {
- terminalWriter
- .okStatus()
- .append("Loading:")
- .normal()
- .append(" " + loadingProgressReceiver.progressState());
+ if (packageProgressReceiver != null) {
+ Pair<String, String> progress = packageProgressReceiver.progressState();
+ terminalWriter.okStatus().append("Loading:").normal().append(" " + progress.getFirst());
+ if (progress.getSecond().length() > 0) {
+ terminalWriter.newline().append(" " + progress.getSecond());
+ }
return;
}
if (executionProgressReceiver != null) {
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/LoadingPhaseStartedEvent.java b/src/main/java/com/google/devtools/build/lib/skyframe/LoadingPhaseStartedEvent.java
index e3e7444688..88bb44bfa9 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/LoadingPhaseStartedEvent.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/LoadingPhaseStartedEvent.java
@@ -13,31 +13,23 @@
// limitations under the License.
package com.google.devtools.build.lib.skyframe;
-import java.util.concurrent.atomic.AtomicInteger;
/**
* This event is fired at the beginning of the loading phase.
*/
public final class LoadingPhaseStartedEvent {
- final LoadingProgressReceiver loadingProgressReceiver;
- final AtomicInteger numPackagesLoaded;
+ final PackageProgressReceiver packageProgress;
/**
* Construct the event
*
* @param loadingProgressReceiver a receiver that gets updated about the progress of loading
*/
- public LoadingPhaseStartedEvent(
- LoadingProgressReceiver loadingProgressReceiver, AtomicInteger numPackagesLoaded) {
- this.loadingProgressReceiver = loadingProgressReceiver;
- this.numPackagesLoaded = numPackagesLoaded;
+ public LoadingPhaseStartedEvent(PackageProgressReceiver packageProgress) {
+ this.packageProgress = packageProgress;
}
- public LoadingProgressReceiver getLoadingProgressReceiver() {
- return loadingProgressReceiver;
- }
-
- public AtomicInteger getNumPackagesLoaded() {
- return numPackagesLoaded;
+ public PackageProgressReceiver getPackageProgressReceiver() {
+ return packageProgress;
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java
index 467b7a73f8..cb0d288788 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java
@@ -91,6 +91,7 @@ public class PackageFunction implements SkyFunction {
private final Cache<PackageIdentifier, CacheEntryWithGlobDeps<AstAfterPreprocessing>> astCache;
private final AtomicBoolean showLoadingProgress;
private final AtomicInteger numPackagesLoaded;
+ private final PackageProgressReceiver packageProgress;
private final Profiler profiler = Profiler.instance();
private final Label preludeLabel;
@@ -106,7 +107,8 @@ public class PackageFunction implements SkyFunction {
Cache<PackageIdentifier, CacheEntryWithGlobDeps<Package.Builder>> packageFunctionCache,
Cache<PackageIdentifier, CacheEntryWithGlobDeps<AstAfterPreprocessing>> astCache,
AtomicInteger numPackagesLoaded,
- @Nullable SkylarkImportLookupFunction skylarkImportLookupFunctionForInlining) {
+ @Nullable SkylarkImportLookupFunction skylarkImportLookupFunctionForInlining,
+ @Nullable PackageProgressReceiver packageProgress) {
this.skylarkImportLookupFunctionForInlining = skylarkImportLookupFunctionForInlining;
// Can be null in tests.
this.preludeLabel = packageFactory == null
@@ -118,6 +120,26 @@ public class PackageFunction implements SkyFunction {
this.packageFunctionCache = packageFunctionCache;
this.astCache = astCache;
this.numPackagesLoaded = numPackagesLoaded;
+ this.packageProgress = packageProgress;
+ }
+
+ public PackageFunction(
+ PackageFactory packageFactory,
+ CachingPackageLocator pkgLocator,
+ AtomicBoolean showLoadingProgress,
+ Cache<PackageIdentifier, CacheEntryWithGlobDeps<Package.Builder>> packageFunctionCache,
+ Cache<PackageIdentifier, CacheEntryWithGlobDeps<AstAfterPreprocessing>> astCache,
+ AtomicInteger numPackagesLoaded,
+ @Nullable SkylarkImportLookupFunction skylarkImportLookupFunctionForInlining) {
+ this(
+ packageFactory,
+ pkgLocator,
+ showLoadingProgress,
+ packageFunctionCache,
+ astCache,
+ numPackagesLoaded,
+ skylarkImportLookupFunctionForInlining,
+ null);
}
public void setSkylarkImportLookupFunctionForInliningForTesting(
@@ -1096,6 +1118,9 @@ public class PackageFunction implements SkyFunction {
packageFunctionCache.getIfPresent(packageId);
if (packageFunctionCacheEntry == null) {
profiler.startTask(ProfilerTask.CREATE_PACKAGE, packageId.toString());
+ if (packageProgress != null) {
+ packageProgress.startReadPackage(packageId);
+ }
try {
CacheEntryWithGlobDeps<AstAfterPreprocessing> astCacheEntry =
astCache.getIfPresent(packageId);
@@ -1183,6 +1208,9 @@ public class PackageFunction implements SkyFunction {
packageFunctionCacheEntry =
new CacheEntryWithGlobDeps<>(pkgBuilder, globDepsRequested, null);
numPackagesLoaded.incrementAndGet();
+ if (packageProgress != null) {
+ packageProgress.doneReadPackage(packageId);
+ }
packageFunctionCache.put(packageId, packageFunctionCacheEntry);
} finally {
profiler.completeTask(ProfilerTask.CREATE_PACKAGE);
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PackageProgressReceiver.java b/src/main/java/com/google/devtools/build/lib/skyframe/PackageProgressReceiver.java
new file mode 100644
index 0000000000..4faf952dd9
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/PackageProgressReceiver.java
@@ -0,0 +1,73 @@
+// Copyright 2016 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.skyframe;
+
+import com.google.devtools.build.lib.cmdline.PackageIdentifier;
+
+import com.google.devtools.build.lib.util.Pair;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+
+/**
+ * A class that, when beeing told about start and end of a package
+ * being loaded, keeps track of the loading progress and provides it
+ * as a human-readable string intened for the progress bar.
+ */
+public class PackageProgressReceiver {
+
+ private int packagesCompleted;
+ private Deque<PackageIdentifier> pending = new ArrayDeque<>();
+
+ /**
+ * Register that loading a package has started.
+ */
+ public synchronized void startReadPackage(PackageIdentifier packageId) {
+ pending.addLast(packageId);
+ }
+
+ /**
+ * Register that loding a package has completed.
+ */
+ public synchronized void doneReadPackage(PackageIdentifier packageId) {
+ packagesCompleted++;
+ pending.remove(packageId);
+ }
+
+ /**
+ * Reset all instance variables of this object to a state equal to that of a newly
+ * constructed object.
+ */
+ public synchronized void reset() {
+ packagesCompleted = 0;
+ pending = new ArrayDeque<>();
+ }
+
+ /**
+ * Return the ordered pair of a consistent snapshot of the state, consisting of a human-readable
+ * description of the progress achieved so far and a human readable description of the currently
+ * running activities. The later always include the oldest loading package not finished loading.
+ */
+ public synchronized Pair<String, String> progressState() {
+ String progress = "" + packagesCompleted + " packages loaded";
+ StringBuffer activity = new StringBuffer();
+ if (pending.size() > 0) {
+ activity.append("currently loading: ").append(pending.peekFirst().toString());
+ if (pending.size() > 1) {
+ activity.append(" ... (" + pending.size() + " packages)");
+ }
+ }
+ return new Pair<String, String>(progress, activity.toString());
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
index 201000d195..2246515a36 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
@@ -200,6 +200,7 @@ public abstract class SkyframeExecutor implements WalkableGraphFactory {
newAstCache();
private final AtomicInteger numPackagesLoaded = new AtomicInteger(0);
+ private final PackageProgressReceiver packageProgress = new PackageProgressReceiver();
protected SkyframeBuildView skyframeBuildView;
private ActionLogBufferPathGenerator actionLogBufferPathGenerator;
@@ -368,7 +369,8 @@ public abstract class SkyframeExecutor implements WalkableGraphFactory {
packageFunctionCache,
astCache,
numPackagesLoaded,
- ruleClassProvider));
+ ruleClassProvider,
+ packageProgress));
map.put(SkyFunctions.PACKAGE_ERROR, new PackageErrorFunction());
map.put(SkyFunctions.TARGET_MARKER, new TargetMarkerFunction());
map.put(SkyFunctions.TRANSITIVE_TARGET, new TransitiveTargetFunction(ruleClassProvider));
@@ -420,7 +422,8 @@ public abstract class SkyframeExecutor implements WalkableGraphFactory {
Cache<PackageIdentifier, CacheEntryWithGlobDeps<Builder>> packageFunctionCache,
Cache<PackageIdentifier, CacheEntryWithGlobDeps<AstAfterPreprocessing>> astCache,
AtomicInteger numPackagesLoaded,
- RuleClassProvider ruleClassProvider) {
+ RuleClassProvider ruleClassProvider,
+ PackageProgressReceiver packageProgress) {
return new PackageFunction(
pkgFactory,
packageManager,
@@ -428,7 +431,8 @@ public abstract class SkyframeExecutor implements WalkableGraphFactory {
packageFunctionCache,
astCache,
numPackagesLoaded,
- null);
+ null,
+ packageProgress);
}
protected SkyFunction newSkylarkImportLookupFunction(
@@ -936,6 +940,7 @@ public abstract class SkyframeExecutor implements WalkableGraphFactory {
packageFunctionCache.invalidateAll();
astCache.invalidateAll();
numPackagesLoaded.set(0);
+ packageProgress.reset();
// Reset the stateful SkyframeCycleReporter, which contains cycles from last run.
cyclesReporter.set(createCyclesReporter());
@@ -1732,7 +1737,7 @@ public abstract class SkyframeExecutor implements WalkableGraphFactory {
TestFilter.forOptions(options, eventHandler, ruleClassNames));
EvaluationResult<TargetPatternPhaseValue> evalResult;
LoadingProgressReceiver loadingProgressReceiver = new LoadingProgressReceiver();
- eventBus.post(new LoadingPhaseStartedEvent(loadingProgressReceiver, numPackagesLoaded));
+ eventBus.post(new LoadingPhaseStartedEvent(packageProgress));
progressReceiver.loadingProgressReceiver = loadingProgressReceiver;
try {
evalResult =
diff --git a/src/test/java/com/google/devtools/build/lib/runtime/ExperimentalStateTrackerTest.java b/src/test/java/com/google/devtools/build/lib/runtime/ExperimentalStateTrackerTest.java
index a276bc516b..ae6ec139cf 100644
--- a/src/test/java/com/google/devtools/build/lib/runtime/ExperimentalStateTrackerTest.java
+++ b/src/test/java/com/google/devtools/build/lib/runtime/ExperimentalStateTrackerTest.java
@@ -27,9 +27,12 @@ import com.google.devtools.build.lib.actions.Root;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.buildtool.buildevent.TestFilteringCompleteEvent;
import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.skyframe.LoadingPhaseStartedEvent;
+import com.google.devtools.build.lib.skyframe.PackageProgressReceiver;
import com.google.devtools.build.lib.testutil.FoundationTestCase;
import com.google.devtools.build.lib.testutil.LoggingTerminalWriter;
import com.google.devtools.build.lib.testutil.ManualClock;
+import com.google.devtools.build.lib.util.Pair;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.lib.view.test.TestStatus.BlazeTestStatus;
@@ -67,6 +70,35 @@ public class ExperimentalStateTrackerTest extends FoundationTestCase {
}
@Test
+ public void testLoadingActivity() throws IOException {
+ // During loading phase, state and activity, as reported by the PackageProgressReceiver,
+ // should be visible in the progress bar.
+ String state = "42 packages loaded";
+ String activity = "currently loading //src/foo/bar and 17 more";
+ PackageProgressReceiver progress = Mockito.mock(PackageProgressReceiver.class);
+ when(progress.progressState()).thenReturn(new Pair<String, String>(state, activity));
+
+ ManualClock clock = new ManualClock();
+ ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock);
+
+ stateTracker.loadingStarted(new LoadingPhaseStartedEvent(progress));
+
+ LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
+ stateTracker.writeProgressBar(terminalWriter);
+ String output = terminalWriter.getTranscript();
+
+ assertTrue(
+ "Output should indicate that we are in the loading phase, but was:\n" + output,
+ output.contains("Loading"));
+ assertTrue(
+ "Output should contain loading state '" + state + "', but was:\n" + output,
+ output.contains(state));
+ assertTrue(
+ "Output should contain loading state '" + activity + "', but was:\n" + output,
+ output.contains(activity));
+ }
+
+ @Test
public void testActionVisible() throws IOException {
// If there is only one action running, it should be visible
// somewhere in the progress bar, and also the short version thereof.
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/PackageProgressReceiverTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/PackageProgressReceiverTest.java
new file mode 100644
index 0000000000..df35718a42
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/PackageProgressReceiverTest.java
@@ -0,0 +1,77 @@
+// Copyright 2016 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.skyframe;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.google.devtools.build.lib.cmdline.PackageIdentifier;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests {@link PackageProgressReceiver}.
+ */
+@RunWith(JUnit4.class)
+public class PackageProgressReceiverTest {
+
+ @Test
+ public void testPackageVisible() {
+ // If there is only a single package being loaded, it is visible in
+ // the activity part of the progress state.
+ PackageIdentifier id = PackageIdentifier.createInMainRepo("foo/bar/baz");
+ PackageProgressReceiver progress = new PackageProgressReceiver();
+ progress.startReadPackage(id);
+ String activity = progress.progressState().getSecond();
+
+ assertTrue(
+ "Unfinished package '" + id + "' should be visible in activity: " + activity,
+ activity.contains(id.toString()));
+ }
+
+ @Test
+ public void testPackageCounted() {
+ // If the loading of a package is completed, it is no longer visible as activity,
+ // but counted as one package fully loaded.
+ PackageIdentifier id = PackageIdentifier.createInMainRepo("foo/bar/baz");
+ PackageProgressReceiver progress = new PackageProgressReceiver();
+ progress.startReadPackage(id);
+ progress.doneReadPackage(id);
+ String state = progress.progressState().getFirst();
+ String activity = progress.progressState().getSecond();
+
+ assertFalse(
+ "Finished package '" + id + "' should not be visible in activity: " + activity,
+ activity.contains(id.toString()));
+ assertTrue(
+ "Number of completed packages should be visible in state", state.contains("1 package"));
+ }
+
+ @Test
+ public void testReset() {
+ // After resetting, messages should be as immediately after creation.
+ PackageProgressReceiver progress = new PackageProgressReceiver();
+ String defaultState = progress.progressState().getFirst();
+ String defaultActivity = progress.progressState().getSecond();
+ PackageIdentifier id = PackageIdentifier.createInMainRepo("foo/bar/baz");
+ progress.startReadPackage(id);
+ progress.doneReadPackage(id);
+ progress.reset();
+ assertEquals(defaultState, progress.progressState().getFirst());
+ assertEquals(defaultActivity, progress.progressState().getSecond());
+ }
+}
diff --git a/src/test/shell/integration/experimental_ui_test.sh b/src/test/shell/integration/experimental_ui_test.sh
index 490d0fe747..3734b7bb24 100755
--- a/src/test/shell/integration/experimental_ui_test.sh
+++ b/src/test/shell/integration/experimental_ui_test.sh
@@ -198,7 +198,7 @@ function test_loading_progress {
--experimental_skyframe_target_pattern_evaluator pkg:true 2>$TEST_log \
|| fail "bazel test failed"
# some progress indicator is shown during loading
- expect_log 'Loading.*[0-9,]* / [0-9,]*'
+ expect_log 'Loading.*[0-9,]* packages'
}
function test_failure_scrollback_buffer_curses {