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  import org.apache.commons.lang3.StringUtils;
28  import org.eclipse.aether.transfer.TransferCancelledException;
29  import org.eclipse.aether.transfer.TransferEvent;
30  import org.eclipse.aether.transfer.TransferResource;
31  
32  /**
33   * Console download progress meter.
34   *
35   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
36   */
37  public class ConsoleMavenTransferListener extends AbstractMavenTransferListener {
38  
39      private Map<TransferResource, Long> transfers = Collections.synchronizedMap(new LinkedHashMap<>());
40  
41      private boolean printResourceNames;
42      private int lastLength;
43  
44      public ConsoleMavenTransferListener(PrintStream out, boolean printResourceNames) {
45          super(out);
46          this.printResourceNames = printResourceNames;
47      }
48  
49      @Override
50      public synchronized void transferInitiated(TransferEvent event) {
51          overridePreviousTransfer(event);
52  
53          super.transferInitiated(event);
54      }
55  
56      @Override
57      public synchronized void transferCorrupted(TransferEvent event) throws TransferCancelledException {
58          overridePreviousTransfer(event);
59  
60          super.transferCorrupted(event);
61      }
62  
63      @Override
64      public synchronized void transferProgressed(TransferEvent event) throws TransferCancelledException {
65          TransferResource resource = event.getResource();
66          transfers.put(resource, event.getTransferredBytes());
67  
68          StringBuilder buffer = new StringBuilder(128);
69          buffer.append("Progress (").append(transfers.size()).append("): ");
70  
71          synchronized (transfers) {
72              Iterator<Map.Entry<TransferResource, Long>> entries =
73                      transfers.entrySet().iterator();
74              while (entries.hasNext()) {
75                  Map.Entry<TransferResource, Long> entry = entries.next();
76                  long total = entry.getKey().getContentLength();
77                  Long complete = entry.getValue();
78                  buffer.append(getStatus(entry.getKey().getResourceName(), complete, total));
79                  if (entries.hasNext()) {
80                      buffer.append(" | ");
81                  }
82              }
83          }
84  
85          int pad = lastLength - buffer.length();
86          lastLength = buffer.length();
87          pad(buffer, pad);
88          buffer.append('\r');
89          out.print(buffer);
90          out.flush();
91      }
92  
93      private String getStatus(String resourceName, long complete, long total) {
94          FileSizeFormat format = new FileSizeFormat(Locale.ENGLISH);
95          StringBuilder status = new StringBuilder();
96  
97          if (printResourceNames) {
98              status.append(StringUtils.substringAfterLast(resourceName, "/"));
99              status.append(" (");
100         }
101 
102         status.append(format.formatProgress(complete, total));
103 
104         if (printResourceNames) {
105             status.append(")");
106         }
107 
108         return status.toString();
109     }
110 
111     private void pad(StringBuilder buffer, int spaces) {
112         String block = "                                        ";
113         while (spaces > 0) {
114             int n = Math.min(spaces, block.length());
115             buffer.append(block, 0, n);
116             spaces -= n;
117         }
118     }
119 
120     @Override
121     public synchronized void transferSucceeded(TransferEvent event) {
122         transfers.remove(event.getResource());
123         overridePreviousTransfer(event);
124 
125         super.transferSucceeded(event);
126     }
127 
128     @Override
129     public synchronized void transferFailed(TransferEvent event) {
130         transfers.remove(event.getResource());
131         overridePreviousTransfer(event);
132 
133         super.transferFailed(event);
134     }
135 
136     private void overridePreviousTransfer(TransferEvent event) {
137         if (lastLength > 0) {
138             StringBuilder buffer = new StringBuilder(128);
139             pad(buffer, lastLength);
140             buffer.append('\r');
141             out.print(buffer);
142             out.flush();
143             lastLength = 0;
144         }
145     }
146 }