001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.release.plugin.mojos;
018
019import java.io.File;
020import java.io.FileInputStream;
021import java.io.FileOutputStream;
022import java.io.IOException;
023import java.util.ArrayList;
024import java.util.List;
025import java.util.zip.ZipEntry;
026import java.util.zip.ZipOutputStream;
027
028import org.apache.commons.compress.archivers.zip.ParallelScatterZipCreator;
029import org.apache.commons.compress.archivers.zip.ScatterZipOutputStream;
030import org.apache.commons.io.IOUtils;
031import org.apache.commons.lang3.StringUtils;
032import org.apache.maven.plugin.AbstractMojo;
033import org.apache.maven.plugin.MojoExecutionException;
034import org.apache.maven.plugin.MojoFailureException;
035import org.apache.maven.plugins.annotations.LifecyclePhase;
036import org.apache.maven.plugins.annotations.Mojo;
037import org.apache.maven.plugins.annotations.Parameter;
038
039/**
040 * Takes the built <code>./target/site</code> directory and compresses it to
041 * <code>./target/commons-release-plugin/site.zip</code>.
042 *
043 * @author chtompki
044 * @since 1.0
045 * @deprecated - as we no longer wish to compress the site, we are going to put this functionality in the
046 *               {@link CommonsDistributionStagingMojo}.
047 */
048@Deprecated
049@Mojo(name = "compress-site",
050        defaultPhase = LifecyclePhase.POST_SITE,
051        threadSafe = true,
052        aggregator = true)
053public class CommonsSiteCompressionMojo extends AbstractMojo {
054
055    /**
056     * The working directory for the plugin which, assuming the maven uses the default
057     * <code>${project.build.directory}</code>, this becomes <code>target/commons-release-plugin</code>.
058     */
059    @Parameter(defaultValue = "${project.build.directory}/commons-release-plugin",
060            property = "commons.outputDirectory")
061    private File workingDirectory;
062
063    /**
064     */
065    @Parameter(defaultValue = "${project.build.directory}/site", property = "commons.siteOutputDirectory")
066    private File siteDirectory;
067
068    /**
069     * The url of the subversion repository to which we wish the artifacts to be staged. Typicallly
070     * this would need to be of the form:
071     * <code>scm:svn:https://dist.apache.org/repos/dist/dev/commons/foo</code>. Note. that the prefix to the
072     * substring <code>https</code> is a requirement.
073     */
074    @Parameter(defaultValue = "", property = "commons.distSvnStagingUrl")
075    private String distSvnStagingUrl;
076
077    /**
078     * A parameter to generally avoid running unless it is specifically turned on by the consuming module.
079     */
080    @Parameter(defaultValue = "false", property = "commons.release.isDistModule")
081    private Boolean isDistModule;
082
083    /**
084     * A variable for the process of creating the site.zip file.
085     */
086    private ScatterZipOutputStream dirs;
087
088    /**
089     * A second variable for the process of creating the site.zip file.
090     */
091    private ParallelScatterZipCreator scatterZipCreator;
092
093    /**
094     * The list of files to compress into the site.zip file.
095     */
096    private List<File> filesToCompress;
097
098    @Override
099    public void execute() throws MojoExecutionException, MojoFailureException {
100        if (!isDistModule) {
101            getLog().info("This module is marked as a non distribution "
102                    + "or assembly module, and the plugin will not run.");
103            return;
104        }
105        if (StringUtils.isEmpty(distSvnStagingUrl)) {
106            getLog().warn("commons.distSvnStagingUrl is not set, the commons-release-plugin will not run.");
107            return;
108        }
109        if (!siteDirectory.exists()) {
110            getLog().error("\"mvn site\" was not run before this goal, or a siteDirectory did not exist.");
111            throw new MojoFailureException(
112                    "\"mvn site\" was not run before this goal, or a siteDirectory did not exist."
113            );
114        }
115        if (!workingDirectory.exists()) {
116            getLog().info("Current project contains no distributions. Not executing.");
117            return;
118        }
119        try {
120            filesToCompress = new ArrayList<>();
121            getAllSiteFiles(siteDirectory, filesToCompress);
122            writeZipFile(workingDirectory, siteDirectory, filesToCompress);
123        } catch (IOException e) {
124            getLog().error("Failed to create ./target/commons-release-plugin/site.zip: " + e.getMessage(), e);
125            throw new MojoExecutionException(
126                    "Failed to create ./target/commons-release-plugin/site.zip: " + e.getMessage(),
127                    e
128            );
129        }
130    }
131
132    /**
133     * By default this method iterates across the <code>target/site</code> directory and adds all of the files
134     * to the {@link CommonsSiteCompressionMojo#filesToCompress} {@link List}.
135     *
136     * @param siteDirectory the {@link File} that represents the <code>target/site</code> directory.
137     * @param filesToCompress the {@link List} to which to add all the files.
138     */
139    private void getAllSiteFiles(File siteDirectory, List<File> filesToCompress) {
140        File[] files = siteDirectory.listFiles();
141        for (File file : files) {
142            filesToCompress.add(file);
143            if (file.isDirectory()) {
144                getAllSiteFiles(file, filesToCompress);
145            }
146        }
147    }
148
149    /**
150     * A helper method for writing all of the files in our <code>fileList</code> to a <code>site.zip</code> file
151     * in the <code>workingDirectory</code>.
152     *
153     * @param outputDirectory is a {@link File} representing the place to put the site.zip file.
154     * @param directoryToZip is a {@link File} representing the directory of the site (normally
155     *                       <code>target/site</code>).
156     * @param fileList the list of files to be zipped up, generally generated by
157     *                 {@link CommonsSiteCompressionMojo#getAllSiteFiles(File, List)}.
158     * @throws IOException when the copying of the files goes incorrectly.
159     */
160    private void writeZipFile(File outputDirectory, File directoryToZip, List<File> fileList) throws IOException {
161        try (FileOutputStream fos = new FileOutputStream(outputDirectory.getAbsolutePath() + "/site.zip");
162                ZipOutputStream zos = new ZipOutputStream(fos)) {
163            for (File file : fileList) {
164                if (!file.isDirectory()) { // we only zip files, not directories
165                    addToZip(directoryToZip, file, zos);
166                }
167            }
168        }
169    }
170
171    /**
172     * Given the <code>directoryToZip</code> we add the <code>file</code> to the zip archive represented by
173     * <code>zos</code>.
174     *
175     * @param directoryToZip a {@link File} representing the directory from which the file exists that we are
176     *                       compressing. Generally this is <code>target/site</code>.
177     * @param file a {@link File} to add to the {@link ZipOutputStream} <code>zos</code>.
178     * @param zos the {@link ZipOutputStream} to which to add our <code>file</code>.
179     * @throws IOException if adding the <code>file</code> doesn't work out properly.
180     */
181    private void addToZip(File directoryToZip, File file, ZipOutputStream zos) throws IOException {
182        try (FileInputStream fis = new FileInputStream(file)) {
183            // we want the zipEntry's path to be a relative path that is relative
184            // to the directory being zipped, so chop off the rest of the path
185            String zipFilePath = file.getCanonicalPath().substring(directoryToZip.getCanonicalPath().length() + 1,
186                    file.getCanonicalPath().length());
187            ZipEntry zipEntry = new ZipEntry(zipFilePath);
188            zos.putNextEntry(zipEntry);
189            IOUtils.copy(fis, zos);
190        }
191    }
192}