experimental UI: improve message shortening

When a progress message has to be shortened, as it does not fit in a
line in the progress bar, add a new first attempt: if the message the
path implicit to the label, only shorten that path within the message
(if that gets short enough, leaving a reasonable part of the path);
usually, the additional information is more useful than having a longer
part of the path present.

While there, also fix incorrect length computation in a different case
of message shortening.

--
Change-Id: Ied80e03cace1b249fc0f4e11bce41f2b4207b6ad
Reviewed-on: https://bazel-review.googlesource.com/#/c/3670
MOS_MIGRATED_REVID=122818198
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 9a12eb1..83ff479 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
@@ -20,6 +20,7 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.actions.Action;
 import com.google.devtools.build.lib.actions.ActionCompletionEvent;
+import com.google.devtools.build.lib.actions.ActionOwner;
 import com.google.devtools.build.lib.actions.ActionStartedEvent;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.Root;
@@ -279,6 +280,37 @@
         output.contains(labelA.toString()));
   }
 
+  @Test
+  public void testSensibleShortening() throws Exception {
+    // Verify that in the typical case, we shorten the progress message by shortening
+    // the path implicit in it, that can also be extracted from the label. In particular,
+    // the parts
+    ManualClock clock = new ManualClock();
+    ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock, 70);
+    Action action = mockAction(
+        "Building some/very/very/long/path/for/some/library/directory/foo.jar (42 source files)",
+        "/home/user/bazel/out/abcdef/some/very/very/long/path/for/some/library/directory/foo.jar");
+    Label label =
+        Label.parseAbsolute("//some/very/very/long/path/for/some/library/directory:libfoo");
+    ActionOwner owner = new ActionOwner(label, null, null, null, "fedcba", null);
+    when(action.getOwner()).thenReturn(owner);
+
+    clock.advanceMillis(TimeUnit.SECONDS.toMillis(3));
+    stateTracker.actionStarted(new ActionStartedEvent(action, clock.nanoTime()));
+    clock.advanceMillis(TimeUnit.SECONDS.toMillis(5));
+
+    LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
+    stateTracker.writeProgressBar(terminalWriter);
+    String output = terminalWriter.getTranscript();
+
+    assertTrue(
+        "Progress bar should contain 'Building ', but was:\n" + output,
+        output.contains("Building "));
+    assertTrue(
+        "Progress bar should contain 'foo.jar (42 source files)', but was:\n" + output,
+        output.contains("foo.jar (42 source files)"));
+  }
+
   private void doTestOutputLength(boolean withTest, int actions) throws Exception {
     // If we target 70 characters, then there should be enough space to both,
     // keep the line limit, and show the local part of the running actions and