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         String direction = event.getRequestType() == TransferEvent.RequestType.PUT ? "to" : "from";
221 
222         TransferResource resource = event.getResource();
223         StringBuilder message = new StringBuilder();
224         message.append( action ).append( ' ' ).append( direction ).append( ' ' ).append( resource.getRepositoryId() );
225         message.append( ": " );
226         message.append( resource.getRepositoryUrl() ).append( resource.getResourceName() );
227 
228         out.println( message.toString() );
229     }
230 
231     @Override
232     public void transferCorrupted( TransferEvent event )
233         throws TransferCancelledException
234     {
235         TransferResource resource = event.getResource();
236         // TODO This needs to be colorized
237         out.println( "[WARNING] " + event.getException().getMessage() + " from " + resource.getRepositoryId() + " for "
238             + resource.getRepositoryUrl() + resource.getResourceName() );
239     }
240 
241     @Override
242     public void transferSucceeded( TransferEvent event )
243     {
244         String action = ( event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploaded" : "Downloaded" );
245         String direction = event.getRequestType() == TransferEvent.RequestType.PUT ? "to" : "from";
246 
247         TransferResource resource = event.getResource();
248         long contentLength = event.getTransferredBytes();
249         FileSizeFormat format = new FileSizeFormat( Locale.ENGLISH );
250 
251         StringBuilder message = new StringBuilder();
252         message.append( action ).append( ' ' ).append( direction ).append( ' ' ).append( resource.getRepositoryId() );
253         message.append( ": " );
254         message.append( resource.getRepositoryUrl() ).append( resource.getResourceName() );
255         message.append( " (" ).append( format.format( contentLength ) );
256 
257         long duration = System.currentTimeMillis() - resource.getTransferStartTime();
258         if ( duration > 0L )
259         {
260             double bytesPerSecond = contentLength / ( duration / 1000.0 );
261             message.append( " at " ).append( format.format( (long) bytesPerSecond ) ).append( "/s" );
262         }
263 
264         message.append( ')' );
265         out.println( message.toString() );
266     }
267 
268 }