View Javadoc
1   package org.apache.maven.wrapper;
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.BufferedOutputStream;
23  import java.io.BufferedReader;
24  import java.io.File;
25  import java.io.FileOutputStream;
26  import java.io.IOException;
27  import java.io.InputStream;
28  import java.io.InputStreamReader;
29  import java.io.OutputStream;
30  import java.net.URI;
31  import java.util.ArrayList;
32  import java.util.Enumeration;
33  import java.util.Formatter;
34  import java.util.List;
35  import java.util.Locale;
36  import java.util.zip.ZipEntry;
37  import java.util.zip.ZipFile;
38  
39  
40  /**
41   * Maven distribution installer, eventually using a {@link Downloader} first.
42   *
43   * @author Hans Dockter
44   */
45  public class Installer
46  {
47      public static final String DEFAULT_DISTRIBUTION_PATH = "wrapper/dists";
48  
49      private final Downloader download;
50  
51      private final PathAssembler pathAssembler;
52  
53      public Installer( Downloader download, PathAssembler pathAssembler )
54      {
55          this.download = download;
56          this.pathAssembler = pathAssembler;
57      }
58  
59      public File createDist( WrapperConfiguration configuration )
60          throws Exception
61      {
62          URI distributionUrl = configuration.getDistribution();
63  
64          String mvnwRepoUrl = System.getenv( MavenWrapperMain.MVNW_REPOURL );
65          if ( mvnwRepoUrl != null && !mvnwRepoUrl.isEmpty() )
66          {
67              Logger.info( "Detected MVNW_REPOURL environment variable " + mvnwRepoUrl );
68              String mvnPath = distributionUrl.toURL().toString();
69              mvnPath = mvnPath.substring( mvnPath.indexOf( "org/apache/maven" ) );
70              distributionUrl = new URI( mvnwRepoUrl + "/" + mvnPath );
71          }
72  
73          boolean alwaysDownload = configuration.isAlwaysDownload();
74          boolean alwaysUnpack = configuration.isAlwaysUnpack();
75  
76          PathAssembler.LocalDistribution localDistribution = pathAssembler.getDistribution( configuration );
77          Logger.info( "Installing Maven distribution " + localDistribution.getDistributionDir().getAbsolutePath() );
78  
79          File localZipFile = localDistribution.getZipFile();
80          boolean downloaded = false;
81          if ( alwaysDownload || !localZipFile.exists() )
82          {
83              File tmpZipFile = new File( localZipFile.getParentFile(), localZipFile.getName() + ".part" );
84              tmpZipFile.delete();
85              Logger.info( "Downloading " + distributionUrl );
86              download.download( distributionUrl, tmpZipFile );
87              tmpZipFile.renameTo( localZipFile );
88              downloaded = true;
89          }
90  
91          File distDir = localDistribution.getDistributionDir();
92          List<File> dirs = listDirs( distDir );
93  
94          if ( downloaded || alwaysUnpack || dirs.isEmpty() )
95          {
96              for ( File dir : dirs )
97              {
98                  Logger.info( "Deleting directory " + dir.getAbsolutePath() );
99                  deleteDir( dir );
100             }
101             Logger.info( "Unzipping " + localZipFile.getAbsolutePath() + " to " + distDir.getAbsolutePath() );
102             unzip( localZipFile, distDir );
103             dirs = listDirs( distDir );
104             if ( dirs.isEmpty() )
105             {
106                 throw new RuntimeException( String.format( "Maven distribution '%s' does not contain any directory."
107                     + " Expected to find exactly 1 directory.", distDir ) );
108             }
109             setExecutablePermissions( dirs.get( 0 ) );
110         }
111         if ( dirs.size() != 1 )
112         {
113             throw new RuntimeException( String.format( "Maven distribution '%s' contains too many directories."
114                 + " Expected to find exactly 1 directory.", distDir ) );
115         }
116         return dirs.get( 0 );
117     }
118 
119     private List<File> listDirs( File distDir )
120     {
121         List<File> dirs = new ArrayList<File>();
122         if ( distDir.exists() )
123         {
124             for ( File file : distDir.listFiles() )
125             {
126                 if ( file.isDirectory() )
127                 {
128                     dirs.add( file );
129                 }
130             }
131         }
132         return dirs;
133     }
134 
135     private void setExecutablePermissions( File mavenHome )
136     {
137         if ( isWindows() )
138         {
139             return;
140         }
141         File mavenCommand = new File( mavenHome, "bin/mvn" );
142         String errorMessage = null;
143         try
144         {
145             ProcessBuilder pb = new ProcessBuilder( "chmod", "755", mavenCommand.getCanonicalPath() );
146             Process p = pb.start();
147             if ( p.waitFor() == 0 )
148             {
149                 Logger.info( "Set executable permissions for: " + mavenCommand.getAbsolutePath() );
150             }
151             else
152             {
153                 try ( BufferedReader is = new BufferedReader( new InputStreamReader( p.getInputStream() ) );
154                                 Formatter stdout = new Formatter() )
155                 {
156                     String line;
157                     while ( ( line = is.readLine() ) != null )
158                     {
159                         stdout.format( "%s%n", line );
160                     }
161                     errorMessage = stdout.toString();
162                 }
163             }
164         }
165         catch ( IOException | InterruptedException e )
166         {
167             errorMessage = e.getMessage();
168         }
169         if ( errorMessage != null )
170         {
171             Logger.warn( "Could not set executable permissions for: " + mavenCommand.getAbsolutePath() );
172             Logger.warn( "Please do this manually if you want to use Maven." );
173         }
174     }
175 
176     private boolean isWindows()
177     {
178         String osName = System.getProperty( "os.name" ).toLowerCase( Locale.US );
179         if ( osName.indexOf( "windows" ) > -1 )
180         {
181             return true;
182         }
183         return false;
184     }
185 
186     private boolean deleteDir( File dir )
187     {
188         if ( dir.isDirectory() )
189         {
190             String[] children = dir.list();
191             for ( int i = 0; i < children.length; i++ )
192             {
193                 boolean success = deleteDir( new File( dir, children[i] ) );
194                 if ( !success )
195                 {
196                     return false;
197                 }
198             }
199         }
200 
201         // The directory is now empty so delete it
202         return dir.delete();
203     }
204 
205     public void unzip( File zip, File dest )
206         throws IOException
207     {
208         Enumeration entries;
209         ZipFile zipFile = new ZipFile( zip );
210 
211         entries = zipFile.entries();
212 
213         while ( entries.hasMoreElements() )
214         {
215             ZipEntry entry = (ZipEntry) entries.nextElement();
216 
217             if ( entry.isDirectory() )
218             {
219                 ( new File( dest, entry.getName() ) ).mkdirs();
220                 continue;
221             }
222 
223             new File( dest, entry.getName() ).getParentFile().mkdirs();
224 
225             try ( InputStream in = zipFile.getInputStream( entry );
226                             OutputStream out =
227                                 new BufferedOutputStream( new FileOutputStream( new File( dest, entry.getName() ) ) ) )
228             {
229                 byte[] buffer = new byte[1024];
230                 int len;
231 
232                 while ( ( len = in.read( buffer ) ) >= 0 )
233                 {
234                     out.write( buffer, 0, len );
235                 }
236             }
237         }
238         zipFile.close();
239     }
240 }