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 org.apache.commons.compress.archivers.zip.ParallelScatterZipCreator; 020import org.apache.commons.compress.archivers.zip.ScatterZipOutputStream; 021import org.apache.commons.lang3.StringUtils; 022import org.apache.commons.release.plugin.SharedFunctions; 023import org.apache.maven.plugin.AbstractMojo; 024import org.apache.maven.plugin.MojoExecutionException; 025import org.apache.maven.plugin.MojoFailureException; 026import org.apache.maven.plugins.annotations.LifecyclePhase; 027import org.apache.maven.plugins.annotations.Mojo; 028import org.apache.maven.plugins.annotations.Parameter; 029 030import java.io.File; 031import java.io.FileInputStream; 032import java.io.FileOutputStream; 033import java.io.IOException; 034import java.util.ArrayList; 035import java.util.List; 036import java.util.zip.ZipEntry; 037import java.util.zip.ZipOutputStream; 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 */ 046@Mojo(name = "compress-site", 047 defaultPhase = LifecyclePhase.POST_SITE, 048 threadSafe = true, 049 aggregator = true) 050public class CommonsSiteCompressionMojo extends AbstractMojo { 051 052 /** 053 * The working directory for the plugin which, assuming the maven uses the default 054 * <code>${project.build.directory}</code>, this becomes <code>target/commons-release-plugin</code>. 055 */ 056 @Parameter(defaultValue = "${project.build.directory}/commons-release-plugin", 057 property = "commons.outputDirectory") 058 private File workingDirectory; 059 060 /** 061 */ 062 @Parameter(defaultValue = "${project.build.directory}/site", property = "commons.siteOutputDirectory") 063 private File siteDirectory; 064 065 /** 066 * The url of the subversion repository to which we wish the artifacts to be staged. Typicallly 067 * this would need to be of the form: 068 * <code>scm:svn:https://dist.apache.org/repos/dist/dev/commons/foo</code>. Note. that the prefix to the 069 * substring <code>https</code> is a requirement. 070 */ 071 @Parameter(defaultValue = "", property = "commons.distSvnStagingUrl") 072 private String distSvnStagingUrl; 073 074 /** 075 * A parameter to generally avoid running unless it is specifically turned on by the consuming module. 076 */ 077 @Parameter(defaultValue = "false", property = "commons.release.isDistModule") 078 private Boolean isDistModule; 079 080 /** 081 * A variable for the process of creating the site.zip file. 082 */ 083 private ScatterZipOutputStream dirs; 084 085 /** 086 * A second variable for the process of creating the site.zip file. 087 */ 088 private ParallelScatterZipCreator scatterZipCreator; 089 090 /** 091 * The list of files to compress into the site.zip file. 092 */ 093 private List<File> filesToCompress; 094 095 @Override 096 public void execute() throws MojoExecutionException, MojoFailureException { 097 if (!isDistModule) { 098 getLog().info("This module is marked as a non distribution " 099 + "or assembly module, and the plugin will not run."); 100 return; 101 } 102 if (StringUtils.isEmpty(distSvnStagingUrl)) { 103 getLog().warn("commons.distSvnStagingUrl is not set, the commons-release-plugin will not run."); 104 return; 105 } 106 if (!siteDirectory.exists()) { 107 getLog().error("\"mvn site\" was not run before this goal, or a siteDirectory did not exist."); 108 throw new MojoFailureException( 109 "\"mvn site\" was not run before this goal, or a siteDirectory did not exist." 110 ); 111 } 112 if (!workingDirectory.exists()) { 113 getLog().info("Current project contains no distributions. Not executing."); 114 return; 115 } 116 try { 117 filesToCompress = new ArrayList<>(); 118 getAllSiteFiles(siteDirectory, filesToCompress); 119 writeZipFile(workingDirectory, siteDirectory, filesToCompress); 120 } catch (IOException e) { 121 getLog().error("Failed to create ./target/commons-release-plugin/site.zip: " + e.getMessage(), e); 122 throw new MojoExecutionException( 123 "Failed to create ./target/commons-release-plugin/site.zip: " + e.getMessage(), 124 e 125 ); 126 } 127 } 128 129 /** 130 * By default this method iterates across the <code>target/site</code> directory and adds all of the files 131 * to the {@link CommonsSiteCompressionMojo#filesToCompress} {@link List}. 132 * 133 * @param siteDirectory the {@link File} that represents the <code>target/site</code> directory. 134 * @param filesToCompress the {@link List} to which to add all the files. 135 */ 136 private void getAllSiteFiles(File siteDirectory, List<File> filesToCompress) { 137 File[] files = siteDirectory.listFiles(); 138 for (File file : files) { 139 filesToCompress.add(file); 140 if (file.isDirectory()) { 141 getAllSiteFiles(file, filesToCompress); 142 } 143 } 144 } 145 146 /** 147 * A helper method for writing all of the files in our <code>fileList</code> to a <code>site.zip</code> file 148 * in the <code>workingDirectory</code>. 149 * 150 * @param workingDirectory is a {@link File} representing the place to put the site.zip file. 151 * @param directoryToZip is a {@link File} representing the directory of the site (normally 152 * <code>target/site</code>). 153 * @param fileList the list of files to be zipped up, generally generated by 154 * {@link CommonsSiteCompressionMojo#getAllSiteFiles(File, List)}. 155 * @throws IOException when the copying of the files goes incorrectly. 156 */ 157 private void writeZipFile(File workingDirectory, File directoryToZip, List<File> fileList) throws IOException { 158 FileOutputStream fos = new FileOutputStream(workingDirectory.getAbsolutePath() + "/site.zip"); 159 ZipOutputStream zos = new ZipOutputStream(fos); 160 for (File file : fileList) { 161 if (!file.isDirectory()) { // we only zip files, not directories 162 addToZip(directoryToZip, file, zos); 163 } 164 } 165 zos.close(); 166 fos.close(); 167 } 168 169 /** 170 * Given the <code>directoryToZip</code> we add the <code>file</code> to the zip archive represented by 171 * <code>zos</code>. 172 * 173 * @param directoryToZip a {@link File} representing the directory from which the file exists that we are 174 * compressing. Generally this is <code>target/site</code>. 175 * @param file a {@link File} to add to the {@link ZipOutputStream} <code>zos</code>. 176 * @param zos the {@link ZipOutputStream} to which to add our <code>file</code>. 177 * @throws IOException if adding the <code>file</code> doesn't work out properly. 178 */ 179 private void addToZip(File directoryToZip, File file, ZipOutputStream zos) throws IOException { 180 FileInputStream fis = new FileInputStream(file); 181 // we want the zipEntry's path to be a relative path that is relative 182 // to the directory being zipped, so chop off the rest of the path 183 String zipFilePath = file.getCanonicalPath().substring(directoryToZip.getCanonicalPath().length() + 1, 184 file.getCanonicalPath().length()); 185 ZipEntry zipEntry = new ZipEntry(zipFilePath); 186 zos.putNextEntry(zipEntry); 187 byte[] bytes = new byte[SharedFunctions.BUFFER_BYTE_SIZE]; 188 int length; 189 while ((length = fis.read(bytes)) >= 0) { 190 zos.write(bytes, 0, length); 191 } 192 zos.closeEntry(); 193 fis.close(); 194 } 195}