View Javadoc
1   /*
2    * Copyright (C) 2007-2008 JVending Masa
3    * Copyright (C) 2011 Jayway AB
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package com.simpligility.maven.plugins.android.standalonemojos;
18  
19  import com.android.ddmlib.AdbCommandRejectedException;
20  import com.android.ddmlib.IDevice;
21  import com.android.ddmlib.SyncException;
22  import com.android.ddmlib.SyncService;
23  import com.android.ddmlib.TimeoutException;
24  import com.simpligility.maven.plugins.android.AbstractAndroidMojo;
25  import com.simpligility.maven.plugins.android.DeviceCallback;
26  import com.simpligility.maven.plugins.android.common.DeviceHelper;
27  import com.simpligility.maven.plugins.android.common.LogSyncProgressMonitor;
28  import com.simpligility.maven.plugins.android.config.ConfigHandler;
29  import com.simpligility.maven.plugins.android.config.ConfigPojo;
30  import com.simpligility.maven.plugins.android.config.PullParameter;
31  import com.simpligility.maven.plugins.android.configuration.Push;
32  
33  import org.apache.commons.io.FileUtils;
34  import org.apache.maven.plugin.MojoExecutionException;
35  import org.apache.maven.plugin.MojoFailureException;
36  import org.apache.maven.plugins.annotations.Mojo;
37  import org.apache.maven.plugins.annotations.Parameter;
38  
39  import java.io.File;
40  import java.io.IOException;
41  import java.util.Collection;
42  import java.util.HashMap;
43  import java.util.Map;
44  
45  /**
46   * Copy file to all the attached (or specified) devices/emulators.
47   *
48   * @author Manfred Moser - manfred@simpligility.com
49   */
50  @SuppressWarnings( "unused" )
51  @Mojo( name = "push", requiresProject = false )
52  public class PushMojo extends AbstractAndroidMojo
53  {
54  
55      /**
56       * <p>The configuration for the push goal can be set up in the plugin configuration in the pom file as:</p>
57       * <pre>
58       * &lt;push&gt;
59       *     &lt;source&gt;path&lt;/source&gt;
60       *     &lt;destination&gt;path&lt;/destination&gt;
61       * &lt;/push&gt;
62       * </pre>
63       * <p>The parameters can also be configured as property in the pom or settings file
64       * <pre>
65       * &lt;properties&gt;
66       *     &lt;android.push.source&gt;pathondevice&lt;/android.push.source&gt;
67       *     &lt;android.push.destination&gt;path&lt;/android.push.destination&gt;
68       * &lt;/properties&gt;
69       * </pre>
70       * or from command-line with parameter
71       * <code>-Dandroid.push.source=path</code>
72       * and
73       * <code>-Dandroid.push.destination=path</code>.</p>
74       */
75      @Parameter
76      @ConfigPojo
77      private Push push;
78  
79      /**
80       * The file name of the local filesystem file to push to the emulator or
81       * device either as absolute path or relative to the execution folder.
82       * 
83       * If you specify a directory, all containing files will be pushed recursively.
84       */
85      @Parameter( property = "android.push.source" )
86      private String pushSource;
87  
88      @PullParameter( required = true )
89      private String parsedSource;
90  
91      /**
92       * The destination file name as absolute path on the emulator or device.
93       * If the last character is a "/" it will be assumed that the original
94       * base filename should be preserved and a target directory is specified.
95       * This works analogous if the source is a directory.
96       */
97      @Parameter( property = "android.push.destination" )
98      private String pushDestination;
99  
100     @PullParameter( required = true )
101     private String parsedDestination;
102 
103     public void execute() throws MojoExecutionException, MojoFailureException
104     {
105 
106         ConfigHandler configHandler = new ConfigHandler( this, this.session, this.execution );
107         configHandler.parseConfiguration();
108 
109         final Map<String, String> sourceDestinationMap = calculateSourceDestinationMapping();
110 
111         doWithDevices( new DeviceCallback()
112         {
113             public void doWithDevice( final IDevice device ) throws MojoExecutionException
114             {
115                 String deviceLogLinePrefix = DeviceHelper.getDeviceLogLinePrefix( device );
116 
117                 // message will be set in for each loop according to the processed files
118                 String message = "";
119 
120                 try
121                 {
122                     SyncService syncService = device.getSyncService();
123 
124                     for ( Map.Entry<String, String> pushFileEntry : sourceDestinationMap.entrySet() )
125                     {
126                         String sourcePath = pushFileEntry.getKey();
127                         String destinationPath = pushFileEntry.getValue();
128 
129                         message = deviceLogLinePrefix + "Push of " + sourcePath + " to " + destinationPath + " on "
130                                 + DeviceHelper.getDescriptiveName( device );
131 
132                         syncService.pushFile( sourcePath, destinationPath, new LogSyncProgressMonitor( getLog() ) );
133 
134                         getLog().info( message + " successful." );
135                     }
136                 }
137                 catch ( SyncException e )
138                 {
139                     throw new MojoExecutionException( message + " failed.", e );
140                 }
141                 catch ( IOException e )
142                 {
143                     throw new MojoExecutionException( message + " failed.", e );
144                 }
145                 catch ( TimeoutException e )
146                 {
147                     throw new MojoExecutionException( message + " failed.", e );
148                 }
149                 catch ( AdbCommandRejectedException e )
150                 {
151                     throw new MojoExecutionException( message + " failed.", e );
152                 }
153             }
154         } );
155     }
156 
157     /**
158      * Calculates a map which contains all files to be pushed to the device or
159      * emulator. The source filename works as the key while the value is the
160      * destination.
161      *
162      * @return a map with file source -> destination pairs
163      * @throws MojoExecutionException
164      */
165     private Map<String, String> calculateSourceDestinationMapping() throws MojoExecutionException
166     {
167         Map<String, String> result = new HashMap<String, String>();
168 
169         File sourceFile = new File( parsedSource );
170         final String destinationPath;
171         if ( parsedDestination.endsWith( "/" ) )
172         {
173             destinationPath = parsedDestination + sourceFile.getName();
174         }
175         else
176         {
177             destinationPath = parsedDestination;
178         }
179 
180         if ( sourceFile.isFile() )
181         {
182             // only put the source in
183             final String sourcePath = sourceFile.getAbsolutePath();
184             result.put( sourcePath, destinationPath );
185         }
186         else
187         {
188             if ( sourceFile.isDirectory() )
189             {
190                 // find recursively all files to be pushed
191                 @SuppressWarnings( "unchecked" ) Collection<File> filesList = FileUtils
192                         .listFiles( sourceFile, null, true );
193                 for ( File file : filesList )
194                 {
195                     // make the file's path relative - this is kind of a hack but it
196                     // works just fine in this controlled environment
197                     String filePath = file.getAbsolutePath().substring( sourceFile.getAbsolutePath().length() );
198                     filePath = filePath.replace( System.getProperty( "file.separator" ), "/" );
199                     result.put( file.getAbsolutePath(), destinationPath + filePath );
200                 }
201             }
202             else
203             {
204                 throw new MojoExecutionException( "Cannot execute push goal: File or directory "
205                         + sourceFile.getAbsolutePath() + " does not exist." );
206             }
207         }
208         return result;
209     }
210 }