View Javadoc
1   package org.apache.maven.cli.transfer;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.PrintStream;
23  import java.text.DecimalFormat;
24  import java.text.DecimalFormatSymbols;
25  import java.util.Locale;
26  
27  import org.apache.commons.lang3.Validate;
28  import org.eclipse.aether.transfer.AbstractTransferListener;
29  import org.eclipse.aether.transfer.TransferCancelledException;
30  import org.eclipse.aether.transfer.TransferEvent;
31  import org.eclipse.aether.transfer.TransferResource;
32  
33  public abstract class AbstractMavenTransferListener
34      extends AbstractTransferListener
35  {
36  
37      // CHECKSTYLE_OFF: LineLength
38      /**
39       * Formats file size with the associated <a href="https://en.wikipedia.org/wiki/Metric_prefix">SI</a> prefix
40       * (GB, MB, kB) and using the patterns <code>#0.0</code> for numbers between 1 and 10
41       * and <code>###0</code> for numbers between 10 and 1000+ by default.
42       *
43       * @see <a href="https://en.wikipedia.org/wiki/Metric_prefix">https://en.wikipedia.org/wiki/Metric_prefix</a>
44       * @see <a href="https://en.wikipedia.org/wiki/Binary_prefix">https://en.wikipedia.org/wiki/Binary_prefix</a>
45       * @see <a
46       *      href="https://en.wikipedia.org/wiki/Octet_%28computing%29">https://en.wikipedia.org/wiki/Octet_(computing)</a>
47       */
48      // CHECKSTYLE_ON: LineLength
49      // TODO Move me to Maven Shared Utils
50      static class FileSizeFormat
51      {
52          static enum ScaleUnit
53          {
54              BYTE
55              {
56                  @Override
57                  public long bytes()
58                  {
59                      return 1L;
60                  }
61  
62                  @Override
63                  public String symbol()
64                  {
65                      return "B";
66                  }
67              },
68              KILOBYTE
69              {
70                  @Override
71                  public long bytes()
72                  {
73                      return 1000L;
74                  }
75  
76                  @Override
77                  public String symbol()
78                  {
79                      return "kB";
80                  }
81              },
82              MEGABYTE
83              {
84                  @Override
85                  public long bytes()
86                  {
87                      return KILOBYTE.bytes() * KILOBYTE.bytes();
88                  }
89  
90                  @Override
91                  public String symbol()
92                  {
93                      return "MB";
94                  }
95              },
96              GIGABYTE
97              {
98                  @Override
99                  public long bytes()
100                 {
101                     return MEGABYTE.bytes() * KILOBYTE.bytes();
102                 };
103 
104                 @Override
105                 public String symbol()
106                 {
107                     return "GB";
108                 }
109             };
110 
111             public abstract long bytes();
112             public abstract String symbol();
113 
114             public static ScaleUnit getScaleUnit( long size )
115             {
116                 Validate.isTrue( size >= 0L, "file size cannot be negative: %s", size );
117 
118                 if ( size >= GIGABYTE.bytes() )
119                 {
120                     return GIGABYTE;
121                 }
122                 else if ( size >= MEGABYTE.bytes() )
123                 {
124                     return MEGABYTE;
125                 }
126                 else if ( size >= KILOBYTE.bytes() )
127                 {
128                     return KILOBYTE;
129                 }
130                 else
131                 {
132                     return BYTE;
133                 }
134             }
135         }
136 
137         private DecimalFormat smallFormat;
138         private DecimalFormat largeFormat;
139 
140         public FileSizeFormat( Locale locale )
141         {
142             smallFormat = new DecimalFormat( "#0.0", new DecimalFormatSymbols( locale ) );
143             largeFormat = new DecimalFormat( "###0", new DecimalFormatSymbols( locale ) );
144         }
145 
146         public String format( long size )
147         {
148             return format( size, null );
149         }
150 
151         public String format( long size, ScaleUnit unit )
152         {
153             return format( size, unit, false );
154         }
155 
156         public String format( long size, ScaleUnit unit, boolean omitSymbol )
157         {
158             Validate.isTrue( size >= 0L, "file size cannot be negative: %s", size );
159 
160             if ( unit == null )
161             {
162                 unit = ScaleUnit.getScaleUnit( size );
163             }
164 
165             double scaledSize = (double) size / unit.bytes();
166             String scaledSymbol = " " + unit.symbol();
167 
168             if ( omitSymbol )
169             {
170                 scaledSymbol = "";
171             }
172 
173             if ( unit == ScaleUnit.BYTE )
174             {
175                 return largeFormat.format( size ) + scaledSymbol;
176             }
177 
178             if ( scaledSize < 0.05 || scaledSize >= 10.0 )
179             {
180                 return largeFormat.format( scaledSize ) + scaledSymbol;
181             }
182             else
183             {
184                 return smallFormat.format( scaledSize ) + scaledSymbol;
185             }
186         }
187 
188         public String formatProgress( long progressedSize, long size )
189         {
190             Validate.isTrue( progressedSize >= 0L, "progressed file size cannot be negative: %s", progressedSize );
191             Validate.isTrue( size >= 0L && progressedSize <= size || size < 0L,
192                 "progressed file size cannot be greater than size: %s > %s", progressedSize, size );
193 
194             if ( size >= 0L && progressedSize != size )
195             {
196                 ScaleUnit unit = ScaleUnit.getScaleUnit( size );
197                 String formattedProgressedSize = format( progressedSize, unit, true );
198                 String formattedSize = format( size, unit );
199 
200                 return formattedProgressedSize + "/" + formattedSize;
201             }
202             else
203             {
204                 return format( progressedSize );
205             }
206         }
207     }
208 
209     protected PrintStream out;
210 
211     protected AbstractMavenTransferListener( PrintStream out )
212     {
213         this.out = out;
214     }
215 
216     @Override
217     public void transferInitiated( TransferEvent event )
218     {
219         String action = event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploading" : "Downloading";
220 
221         TransferResource resource = event.getResource();
222         out.println( action + ": " + resource.getRepositoryUrl() + resource.getResourceName() );
223     }
224 
225     @Override
226     public void transferCorrupted( TransferEvent event )
227         throws TransferCancelledException
228     {
229         TransferResource resource = event.getResource();
230         // TODO This needs to be colorized
231         out.println( "[WARNING] " + event.getException().getMessage() + " for " + resource.getRepositoryUrl()
232             + resource.getResourceName() );
233     }
234 
235     @Override
236     public void transferSucceeded( TransferEvent event )
237     {
238         TransferResource resource = event.getResource();
239         long contentLength = event.getTransferredBytes();
240 
241         FileSizeFormat format = new FileSizeFormat( Locale.ENGLISH );
242         String result = ( event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploaded" : "Downloaded" );
243         String len = format.format( contentLength );
244 
245         String throughput = "";
246         long duration = System.currentTimeMillis() - resource.getTransferStartTime();
247         if ( duration > 0L )
248         {
249             double bytesPerSecond = contentLength / ( duration / 1000.0 );
250             throughput = " at " + format.format( (long) bytesPerSecond ) + "/s";
251         }
252 
253         out.println( result + ": " + resource.getRepositoryUrl() + resource.getResourceName() + " (" + len
254             + throughput + ")" );
255     }
256 
257 }