001/*
002 * Copyright 2011-2012 Stephen Connolly.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.jszip.maven;
018
019import org.apache.maven.artifact.Artifact;
020import org.apache.maven.artifact.ArtifactUtils;
021import org.apache.maven.execution.MavenSession;
022import org.apache.maven.model.Plugin;
023import org.apache.maven.model.PluginExecution;
024import org.apache.maven.plugin.MavenPluginManager;
025import org.apache.maven.plugin.Mojo;
026import org.apache.maven.plugin.MojoExecution;
027import org.apache.maven.plugin.MojoExecutionException;
028import org.apache.maven.plugin.MojoFailureException;
029import org.apache.maven.plugin.PluginConfigurationException;
030import org.apache.maven.plugin.PluginContainerException;
031import org.apache.maven.plugin.descriptor.MojoDescriptor;
032import org.apache.maven.plugin.descriptor.PluginDescriptor;
033import org.apache.maven.plugins.annotations.Component;
034import org.apache.maven.plugins.annotations.LifecyclePhase;
035import org.apache.maven.plugins.annotations.Parameter;
036import org.apache.maven.plugins.annotations.ResolutionScope;
037import org.apache.maven.project.MavenProject;
038import org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException;
039import org.apache.maven.shared.artifact.filter.collection.FilterArtifacts;
040import org.apache.maven.shared.artifact.filter.collection.ProjectTransitivityFilter;
041import org.apache.maven.shared.artifact.filter.collection.ScopeFilter;
042import org.apache.maven.shared.artifact.filter.collection.TypeFilter;
043import org.codehaus.plexus.archiver.ArchiverException;
044import org.codehaus.plexus.archiver.zip.ZipUnArchiver;
045import org.codehaus.plexus.components.io.fileselectors.IncludeExcludeFileSelector;
046import org.codehaus.plexus.util.FileUtils;
047import org.codehaus.plexus.util.StringUtils;
048
049import java.io.File;
050import java.io.IOException;
051import java.util.List;
052import java.util.Set;
053
054/**
055 * Unpacks all the JSZip dependencies into a web application.
056 */
057@org.apache.maven.plugins.annotations.Mojo(name = "unpack",
058        defaultPhase = LifecyclePhase.GENERATE_RESOURCES,
059        requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME
060)
061public class UnpackMojo extends AbstractJSZipMojo {
062
063    /**
064     * The artifact path mappings for unpacking.
065     */
066    @Parameter(property = "mappings")
067    private Mapping[] mappings;
068
069    /**
070     * The directory where the webapp is built.
071     */
072    @Parameter(defaultValue = "${project.build.directory}/${project.build.finalName}", required = true)
073    private File webappDirectory;
074
075    /**
076     * The Zip unarchiver.
077     */
078    @Component(role = org.codehaus.plexus.archiver.UnArchiver.class, hint = "zip")
079    private ZipUnArchiver zipUnArchiver;
080
081    /**
082     * The reactor projects
083     */
084    @Parameter(property = "reactorProjects", required = true, readonly = true)
085    protected List<MavenProject> reactorProjects;
086
087    /**
088     * The Maven plugin Manager
089     */
090    @Component
091    private MavenPluginManager mavenPluginManager;
092
093    /**
094     * The current build session instance. This is used for plugin manager API calls.
095     */
096    @Parameter(property = "session", required = true, readonly = true)
097    private MavenSession session;
098
099    /**
100     * This plugin's descriptor
101     */
102    @Parameter(property = "plugin", readonly = true)
103    private PluginDescriptor pluginDescriptor;
104
105    /**
106     * A list of &lt;include&gt; elements specifying the files (by pattern) that should be included in
107     * unpacking.
108     */
109    @Parameter
110    private List<String> unpackIncludes;
111
112    /**
113     * A list of &lt;exclude&gt; elements specifying the files (by pattern) that should be excluded from
114     * unpacking. The default is
115     * <pre>
116     *     &lt;unpackExclude&gt;META-INF/maven/&#42;&#42;/pom.&#42;&lt;/unpackExclude&gt;
117     *     &lt;unpackExclude&gt;package.json&lt;/unpackExclude&gt;
118     *     &lt;unpackExclude&gt;&#42;&#42;/&#42;.less&lt;/unpackExclude&gt;
119     *     &lt;unpackExclude&gt;&#42;&#42;/&#42;.sass&lt;/unpackExclude&gt;
120     *     &lt;unpackExclude&gt;&#42;&#42;/&#42;.scss&lt;/unpackExclude&gt;
121     * </pre>
122     */
123    @Parameter
124    private List<String> unpackExcludes;
125
126    /**
127     * @see org.apache.maven.plugin.Mojo#execute()
128     */
129    public void execute()
130            throws MojoExecutionException, MojoFailureException {
131        getLog().info("Starting unpack into " + webappDirectory);
132        FilterArtifacts filter = new FilterArtifacts();
133
134        filter.addFilter(new ProjectTransitivityFilter(project.getDependencyArtifacts(), false));
135
136        filter.addFilter(new ScopeFilter("runtime", ""));
137
138        filter.addFilter(new TypeFilter(JSZIP_TYPE, ""));
139
140        // start with all artifacts.
141        Set<Artifact> artifacts = project.getArtifacts();
142
143        // perform filtering
144        try {
145            artifacts = filter.filter(artifacts);
146        } catch (ArtifactFilterException e) {
147            throw new MojoExecutionException(e.getMessage(), e);
148        }
149
150        String includes;
151        String excludes;
152        if (unpackIncludes != null && !unpackIncludes.isEmpty()) {
153            includes = StringUtils.join(unpackIncludes.iterator(), ",");
154        } else {
155            includes = null;
156        }
157
158        if (unpackExcludes != null && !unpackExcludes.isEmpty()) {
159            excludes = StringUtils.join(unpackExcludes.iterator(), ",");
160        } else {
161            excludes="META-INF/maven/**/pom.*,package.json,**/*.less,**/*.sass,**/*.scss";
162        }
163
164
165
166        for (Artifact artifact : artifacts) {
167            String path = getPath(artifact);
168            File artifactDirectory;
169            if (StringUtils.isBlank(path)) {
170                getLog().info("Unpacking " + ArtifactUtils.key(artifact));
171                artifactDirectory = webappDirectory;
172            } else {
173                getLog().info("Unpacking " + ArtifactUtils.key(artifact) + " at path " + path);
174                artifactDirectory = new File(webappDirectory, path);
175            }
176            unpack(artifact, artifactDirectory, includes, excludes);
177        }
178    }
179
180    private String getPath(Artifact artifact) {
181        if (mappings == null) return "";
182        for (Mapping mapping: mappings) {
183            if (mapping.isMatch(artifact))
184                return StringUtils.clean(mapping.getPath());
185        }
186        return "";
187    }
188
189    protected void unpack(Artifact artifact, File location, String includes, String excludes)
190            throws MojoExecutionException {
191        File file = artifact.getFile();
192        if (file.isDirectory()) {
193            MavenProject fromReactor = findProject(reactorProjects, artifact);
194            if (fromReactor != null) {
195                MavenSession session = this.session.clone();
196                session.setCurrentProject(fromReactor);
197                Plugin plugin = findThisPluginInProject(fromReactor);
198                try {
199                    // we cheat here and use our version of the plugin... but this is less of a cheat than the only
200                    // other way which is via reflection.
201                    MojoDescriptor jszipDescriptor = findMojoDescriptor(this.pluginDescriptor, JSZipMojo.class);
202
203                    for (PluginExecution pluginExecution : plugin.getExecutions()) {
204                        if (!pluginExecution.getGoals().contains(jszipDescriptor.getGoal())) {
205                            continue;
206                        }
207                        MojoExecution mojoExecution =
208                                createMojoExecution(plugin, pluginExecution, jszipDescriptor);
209                        JSZipMojo mojo = (JSZipMojo) mavenPluginManager
210                                .getConfiguredMojo(Mojo.class, session, mojoExecution);
211                        try {
212                            File contentDirectory = mojo.getContentDirectory();
213                            if (contentDirectory.isDirectory()) {
214                                FileUtils.copyDirectory(contentDirectory, location);
215                            }
216                            File resourcesDirectory = mojo.getResourcesDirectory();
217                            if (resourcesDirectory.isDirectory()) {
218                                FileUtils.copyDirectory(resourcesDirectory, location);
219                            }
220                        } finally {
221                            mavenPluginManager.releaseMojo(mojo, mojoExecution);
222                        }
223                    }
224                } catch (PluginConfigurationException e) {
225                    throw new MojoExecutionException(e.getMessage(), e);
226                } catch (IOException e) {
227                    throw new MojoExecutionException(e.getMessage(), e);
228                } catch (PluginContainerException e) {
229                    throw new MojoExecutionException(e.getMessage(), e);
230                }
231            } else {
232                throw new MojoExecutionException("Cannot find jzsip artifact: " + artifact.getId());
233            }
234        } else {
235            try {
236                location.mkdirs();
237
238                zipUnArchiver.setSourceFile(file);
239
240                zipUnArchiver.setDestDirectory(location);
241
242                if (StringUtils.isNotEmpty(excludes) || StringUtils.isNotEmpty(includes)) {
243                    IncludeExcludeFileSelector[] selectors =
244                            new IncludeExcludeFileSelector[]{new IncludeExcludeFileSelector()};
245
246                    if (StringUtils.isNotEmpty(excludes)) {
247                        selectors[0].setExcludes(excludes.split(","));
248                    }
249
250                    if (StringUtils.isNotEmpty(includes)) {
251                        selectors[0].setIncludes(includes.split(","));
252                    }
253
254                    zipUnArchiver.setFileSelectors(selectors);
255                }
256
257                zipUnArchiver.extract();
258            } catch (ArchiverException e) {
259                e.printStackTrace();
260                throw new MojoExecutionException("Error unpacking file: " + file + " to: " + location + "\r\n"
261                        + e.toString(), e);
262            }
263        }
264    }
265
266}