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