View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.cli.transfer;
20  
21  import java.io.PrintStream;
22  import java.util.Collections;
23  import java.util.Iterator;
24  import java.util.LinkedHashMap;
25  import java.util.Locale;
26  import java.util.Map;
27  
28  import org.apache.commons.lang3.StringUtils;
29  import org.eclipse.aether.transfer.TransferCancelledException;
30  import org.eclipse.aether.transfer.TransferEvent;
31  import org.eclipse.aether.transfer.TransferResource;
32  
33  /**
34   * Console download progress meter.
35   *
36   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
37   */
38  public class ConsoleMavenTransferListener extends AbstractMavenTransferListener {
39  
40      private Map<TransferResource, Long> transfers = Collections.synchronizedMap(new LinkedHashMap<>());
41  
42      private boolean printResourceNames;
43      private int lastLength;
44  
45      public ConsoleMavenTransferListener(PrintStream out, boolean printResourceNames) {
46          super(out);
47          this.printResourceNames = printResourceNames;
48      }
49  
50      @Override
51      public synchronized void transferInitiated(TransferEvent event) {
52          overridePreviousTransfer(event);
53  
54          super.transferInitiated(event);
55      }
56  
57      @Override
58      public synchronized void transferCorrupted(TransferEvent event) throws TransferCancelledException {
59          overridePreviousTransfer(event);
60  
61          super.transferCorrupted(event);
62      }
63  
64      @Override
65      public synchronized void transferProgressed(TransferEvent event) throws TransferCancelledException {
66          TransferResource resource = event.getResource();
67          transfers.put(resource, event.getTransferredBytes());
68  
69          StringBuilder buffer = new StringBuilder(128);
70          buffer.append("Progress (").append(transfers.size()).append("): ");
71  
72          synchronized (transfers) {
73              Iterator<Map.Entry<TransferResource, Long>> entries =
74                      transfers.entrySet().iterator();
75              while (entries.hasNext()) {
76                  Map.Entry<TransferResource, Long> entry = entries.next();
77                  long total = entry.getKey().getContentLength();
78                  Long complete = entry.getValue();
79                  buffer.append(getStatus(entry.getKey().getResourceName(), complete, total));
80                  if (entries.hasNext()) {
81                      buffer.append(" | ");
82                  }
83              }
84          }
85  
86          int pad = lastLength - buffer.length();
87          lastLength = buffer.length();
88          pad(buffer, pad);
89          buffer.append('\r');
90          out.print(buffer);
91          out.flush();
92      }
93  
94      private String getStatus(String resourceName, long complete, long total) {
95          FileSizeFormat format = new FileSizeFormat(Locale.ENGLISH);
96          StringBuilder status = new StringBuilder();
97  
98          if (printResourceNames) {
99              status.append(StringUtils.substringAfterLast(resourceName, "/"));
100             status.append(" (");
101         }
102 
103         status.append(format.formatProgress(complete, total));
104 
105         if (printResourceNames) {
106             status.append(")");
107         }
108 
109         return status.toString();
110     }
111 
112     private void pad(StringBuilder buffer, int spaces) {
113         String block = "                                        ";
114         while (spaces > 0) {
115             int n = Math.min(spaces, block.length());
116             buffer.append(block, 0, n);
117             spaces -= n;
118         }
119     }
120 
121     @Override
122     public synchronized void transferSucceeded(TransferEvent event) {
123         transfers.remove(event.getResource());
124         overridePreviousTransfer(event);
125 
126         super.transferSucceeded(event);
127     }
128 
129     @Override
130     public synchronized void transferFailed(TransferEvent event) {
131         transfers.remove(event.getResource());
132         overridePreviousTransfer(event);
133 
134         super.transferFailed(event);
135     }
136 
137     private void overridePreviousTransfer(TransferEvent event) {
138         if (lastLength > 0) {
139             StringBuilder buffer = new StringBuilder(128);
140             pad(buffer, lastLength);
141             buffer.append('\r');
142             out.print(buffer);
143             out.flush();
144             lastLength = 0;
145         }
146     }
147 }